}
},
- inspectorTabClicked: function(ev, tab) {
- if (iPhone) ev.stopPropagation();
-
- // select this tab and deselect the others
- $(tab).addClass('selected').siblings().removeClass('selected');
-
- // show this tab and hide the others
- $('#'+tab.id+'_container').show().siblings('.inspector_container').hide();
-
- this.hideiPhoneAddressbar();
- this.updatePeersLists();
- this.updateTrackersLists();
- this.updateFileList();
- },
-
filesSelectAllClicked: function() {
var t = this._file_torrent;
if (t)
return false; // to prevent the event from bubbling up
},
- /*
- * Update the inspector with the latest data for the selected torrents
- */
- updateInspector: function()
- {
- if (!this[Prefs._ShowInspector])
- return;
- var torrents = this.getSelectedTorrents();
- if (!torrents.length && iPhone) {
- this.setInspectorVisible(false);
- return;
- }
+ onTorrentChanged: function(ev)
+ {
+ this.refilterSoon();
+
+ // if this torrent is in the inspector, refresh the inspector
+ if (this[Prefs._ShowInspector])
+ if (this.getSelectedTorrentIds().indexOf(ev.target.getId()) !== -1)
+ this.updateInspector();
+ },
- var creator = 'N/A';
- var comment = 'N/A';
- var download_dir = 'N/A';
- var date_created = 'N/A';
- var error = 'None';
- var hash = 'N/A';
- var have_public = false;
- var have_private = false;
- var name;
- var sizeWhenDone = 0;
- var sizeDone = 0;
- var total_completed = 0;
- var total_download = 0;
- var total_download_peers = 0;
- var total_download_speed = 0;
- var total_availability = 0;
- var total_size = 0;
- var total_state = [ ];
- var pieces = 'N/A';
- var total_upload = 0;
- var total_upload_peers = 0;
- var total_upload_speed = 0;
- var total_verified = 0;
- var na = 'N/A';
- var tab = this._inspector._info_tab;
+ updateFromTorrentGet: function(updates, removed_ids)
+ {
+ var new_ids = [];
- $("#torrent_inspector_size, .inspector_row div").css('color', '#222');
+ for (var i=0, o; o=updates[i]; ++i) {
+ var t;
+ var id = o.id;
+ if ((t = this._torrents[id]))
+ t.refresh(o);
+ else {
+ t = this._torrents[id] = new Torrent(o);
+ $(t).bind('dataChanged',function(ev) {tr.onTorrentChanged(ev);});
+ new_ids.push(id);
+ }
+ }
- if (torrents.length == 0)
- {
- setInnerHTML(tab.name, 'No Selection');
- setInnerHTML(tab.size, na);
- setInnerHTML(tab.pieces, na);
- setInnerHTML(tab.hash, na);
- setInnerHTML(tab.state, na);
- setInnerHTML(tab.download_speed, na);
- setInnerHTML(tab.upload_speed, na);
- setInnerHTML(tab.uploaded, na);
- setInnerHTML(tab.downloaded, na);
- setInnerHTML(tab.availability, na);
- setInnerHTML(tab.ratio, na);
- setInnerHTML(tab.have, na);
- setInnerHTML(tab.upload_to, na);
- setInnerHTML(tab.download_from, na);
- setInnerHTML(tab.secure, na);
- setInnerHTML(tab.creator_date, na);
- setInnerHTML(tab.progress, na);
- setInnerHTML(tab.comment, na);
- setInnerHTML(tab.creator, na);
- setInnerHTML(tab.download_dir, na);
- setInnerHTML(tab.error, na);
- this.updateFileList();
- this.updatePeersLists();
- this.updateTrackersLists();
- $("#torrent_inspector_size, .inspector_row > div:contains('N/A')").css('color', '#666');
- return;
+ if (new_ids.length) {
+ var tr = this;
+ this.remote.getTorrentInitial(new_ids, function(a,b){tr.updateFromTorrentGet(a,b);});
+ this.refilterSoon();
}
- name = torrents.length == 1
- ? torrents[0].getName()
- : torrents.length+' Transfers Selected';
+ if (removed_ids) {
+ this.deleteTorrents(removed_ids);
+ this.refilterSoon();
+ }
+ },
- if (torrents.length == 1)
- {
- var text;
- var t = torrents[0];
- var err = t.getErrorMessage();
- if (err)
- error = err;
- if ((text = t.getComment()))
- comment = text;
- if ((text = t.getCreator()))
- creator = text;
- if ((text = t.getDownloadDir()))
- download_dir = text;
+ refreshTorrents: function(ids) {
+ if (!ids)
+ ids = 'recently-active';
+ var tr = this;
+ this.remote.getTorrentStats(ids, function(a,b){tr.updateFromTorrentGet(a,b);});
+ },
+ initializeAllTorrents: function() {
+ var tr = this;
+ this.remote.getTorrentInitial(null, function(a,b){tr.updateFromTorrentGet(a,b);});
+ },
+ refreshMetadata: function(ids) {
+ var tr = this;
+ this.remote.getTorrentMetadata(ids, function(a,b){tr.updateFromTorrentGet(a,b);});
+ },
+ refreshInspectorTorrents: function(full) {
+ var tr = this;
+ var ids = tr.getSelectedTorrentIds();
+ if (ids.length > 0)
+ this.remote.getTorrentDetails(ids, full, function(a,b){tr.updateFromTorrentGet(a,b);});
+ },
- hash = t.getHashString();
- pieces = [ t.getPieceCount(), 'pieces @', Transmission.fmt.mem(t.getPieceSize()) ].join(' ');
- date_created = Transmission.fmt.timestamp(t.getDateCreated());
- }
+ onRowClicked: function(ev, row)
+ {
+ // Prevents click carrying to parent element
+ // which deselects all on click
+ ev.stopPropagation();
+ // but still hide the context menu if it is showing
+ $('#jqContextMenu').hide();
- for (var i=0, t; t=torrents[i]; ++i) {
- var l = t.getLeftUntilDone();
- var d = t.getSizeWhenDone();
- sizeWhenDone += d;
- sizeDone += d - l;
- 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 - l + t.getDesiredAvailable();
+ // 'Apple' button emulation on PC :
+ // Need settable meta-key and ctrl-key variables for mac emulation
+ var meta_key = ev.metaKey;
+ if (ev.ctrlKey && navigator.appVersion.toLowerCase().indexOf("mac") == -1)
+ meta_key = true;
- var s = t.getStateString();
- if (total_state.indexOf(s) == -1)
- total_state.push(s);
+ // Shift-Click - selects a range from the last-clicked row to this one
+ if (iPhone) {
+ if (row.isSelected())
+ this.setInspectorVisible(true);
+ this.setSelectedRow(row);
- if (t.getPrivateFlag())
- have_private = true;
- else
- have_public = true;
- }
+ } else if (ev.shiftKey) {
+ this.selectRange(row);
+ // Need to deselect any selected text
+ window.focus();
- var private_string = '';
- var fmt = Transmission.fmt;
- if (have_private && have_public) private_string = 'Mixed';
- else if (have_private) private_string = 'Private Torrent';
- else if (have_public) private_string = 'Public Torrent';
+ // Apple-Click, not selected
+ } else if (!row.isSelected() && meta_key) {
+ this.selectRow(row);
- setInnerHTML(tab.name, name);
- setInnerHTML(tab.size, torrents.length ? fmt.size(total_size) : na);
- setInnerHTML(tab.pieces, pieces);
- setInnerHTML(tab.hash, hash);
- setInnerHTML(tab.state, total_state.join('/'));
- setInnerHTML(tab.download_speed, torrents.length ? fmt.speedBps(total_download_speed) : na);
- setInnerHTML(tab.upload_speed, torrents.length ? fmt.speedBps(total_upload_speed) : na);
- setInnerHTML(tab.uploaded, torrents.length ? fmt.size(total_upload) : na);
- setInnerHTML(tab.downloaded, torrents.length ? fmt.size(total_download) : na);
- setInnerHTML(tab.availability, torrents.length ? fmt.percentString(Math.ratio(total_availability*100, sizeWhenDone)) + '%' : na);
- setInnerHTML(tab.ratio, torrents.length ? fmt.ratioString(Math.ratio(total_upload, total_download)) : na);
- setInnerHTML(tab.have, torrents.length ? fmt.size(total_completed) + ' (' + fmt.size(total_verified) + ' verified)' : na);
- setInnerHTML(tab.upload_to, torrents.length ? total_upload_peers : na);
- setInnerHTML(tab.download_from, torrents.length ? total_download_peers : na);
- setInnerHTML(tab.secure, private_string);
- setInnerHTML(tab.creator_date, date_created);
- setInnerHTML(tab.progress, torrents.length ? fmt.percentString(Math.ratio(sizeDone*100, sizeWhenDone)) + '%' : na);
- setInnerHTML(tab.comment, comment);
- setInnerHTML(tab.creator, creator);
- setInnerHTML(tab.download_dir, download_dir);
- setInnerHTML(tab.error, error);
+ // Regular Click, not selected
+ } else if (!row.isSelected()) {
+ this.setSelectedRow(row);
- this.updatePeersLists();
- this.updateTrackersLists();
- $(".inspector_row > div:contains('N/A')").css('color', '#666');
- this.updateFileList();
- },
+ // Apple-Click, selected
+ } else if (row.isSelected() && meta_key) {
+ this.deselectRow(row);
- onFileWantedToggled: function(row, want) {
- var command = want ? 'files-wanted' : 'files-unwanted';
- this.changeFileCommand(command, [ row ]);
- },
- onFilePriorityToggled: function(row, priority) {
- var command;
- switch(priority) {
- case -1: command = 'priority-low'; break;
- case 1: command = 'priority-high'; break;
- default: command = 'priority-normal'; break;
+ // Regular Click, selected
+ } else if (row.isSelected()) {
+ this.setSelectedRow(row);
}
- this.changeFileCommand(command, [ row ]);
+
+ this._last_torrent_clicked = row.getTorrentId();
},
- clearFileList: function()
+
+ deleteTorrents: function(torrent_ids)
{
- $(this._inspector_file_list).empty();
- delete this._file_torrent;
- delete this._file_rows;
- },
- updateFileList: function()
- {
- if (!$(this._inspector_file_list).is(':visible'))
- return;
-
- var sel = this.getSelectedTorrents();
- if (sel.length !== 1) {
- this.clearFileList();
- return;
+ if (torrent_ids && torrent_ids.length)
+ {
+ for (var i=0, id; id=torrent_ids[i]; ++i)
+ delete this._torrents[id];
+ this.refilter();
}
+ },
- var torrent = sel[0];
- if (torrent === this._files_torrent)
- if(torrent.getFileCount() === (this._files ? this._files.length: 0))
- return;
+ updateStatusbar: function()
+ {
+ this.refreshFilterButton();
- // build the file list
- this.clearFileList();
- this._file_torrent = torrent;
- var n = torrent.getFileCount();
- this._file_rows = [];
- var fragment = document.createDocumentFragment();
- var tr = this;
- for (var i=0; i<n; ++i) {
- var row = this._file_rows[i] = new FileRow(torrent, i);
- fragment.appendChild(row.getElement());
- $(row).bind('wantedToggled',function(e,row,want) {tr.onFileWantedToggled(row,want);});
- $(row).bind('priorityToggled',function(e,row,priority) {tr.onFilePriorityToggled(row,priority);});
+ // up/down speed
+ var u=0, d=0;
+ var torrents = this.getAllTorrents();
+ for (var i=0, row; row=torrents[i]; ++i) {
+ u += row.getUploadSpeed();
+ d += row.getDownloadSpeed();
}
- this._inspector_file_list.appendChild(fragment);
+ setInnerHTML($('#statusbar #speed-up-label')[0], '↑ ' + Transmission.fmt.speedBps(u));
+ setInnerHTML($('#statusbar #speed-dn-label')[0], '↓ ' + Transmission.fmt.speedBps(d));
},
- updatePeersLists: function()
+ /*
+ * Select a torrent file to upload
+ * FIXME
+ */
+ uploadTorrentFile: function(confirmed)
{
- if (!$(this._inspector_peers_list).is(':visible'))
- return;
-
- var html = [ ];
- var fmt = Transmission.fmt;
- var torrents = this.getSelectedTorrents();
-
- for (var k=0, torrent; torrent=torrents[k]; ++k) {
- var peers = torrent.getPeers();
- html.push('<div class="inspector_group">');
- if (torrents.length > 1) {
- html.push('<div class="inspector_torrent_label">', torrent.getName(), '</div>');
- }
- if (!peers || !peers.length) {
- html.push('<br></div>'); // firefox won't paint the top border if the div is empty
- continue;
+ // Display the upload dialog
+ if (! confirmed) {
+ $('input#torrent_upload_file').attr('value', '');
+ $('input#torrent_upload_url').attr('value', '');
+ $('input#torrent_auto_start').attr('checked', $('#prefs_form #auto_start')[0].checked);
+ $('#upload_container').show();
+ $('#torrent_upload_url').focus();
+ if (!iPhone && Safari3) {
+ setTimeout("$('div#upload_container div.dialog_window').css('top', '0px');",10);
}
- html.push('<table class="peer_list">',
- '<tr class="inspector_peer_entry even">',
- '<th class="encryptedCol"></th>',
- '<th class="upCol">Up</th>',
- '<th class="downCol">Down</th>',
- '<th class="percentCol">%</th>',
- '<th class="statusCol">Status</th>',
- '<th class="addressCol">Address</th>',
- '<th class="clientCol">Client</th>',
- '</tr>');
- for (var i=0, peer; peer=peers[i]; ++i) {
- var parity = ((i+1) % 2 == 0 ? 'even' : 'odd');
- html.push('<tr class="inspector_peer_entry ', parity, '">',
- '<td>', (peer.isEncrypted ? '<img src="images/graphics/lock_icon.png" alt="Encrypted"/>' : ''), '</td>',
- '<td>', (peer.rateToPeer ? fmt.speedBps(peer.rateToPeer) : ''), '</td>',
- '<td>', (peer.rateToClient ? fmt.speedBps(peer.rateToClient) : ''), '</td>',
- '<td class="percentCol">', Math.floor(peer.progress*100), '%', '</td>',
- '<td>', fmt.peerStatus(peer.flagStr), '</td>',
- '<td>', peer.address, '</td>',
- '<td class="clientCol">', peer.clientName, '</td>',
- '</tr>');
+
+ // Submit the upload form
+ } else {
+ var tr = this;
+ var args = { };
+ var paused = !$('#torrent_auto_start').is(':checked');
+ if ('' != $('#torrent_upload_url').val()) {
+ tr.remote.addTorrentByUrl($('#torrent_upload_url').val(), { paused: paused });
+ } else {
+ args.url = '../upload?paused=' + paused;
+ args.type = 'POST';
+ args.data = { 'X-Transmission-Session-Id' : tr.remote._token };
+ args.dataType = 'xml';
+ args.iframe = true;
+ args.success = function() {
+ tr.refreshTorrents();
+ tr.togglePeriodicRefresh(true);
+ };
+ tr.togglePeriodicRefresh(false);
+ $('#torrent_upload_form').ajaxSubmit(args);
}
- html.push('</table></div>');
}
-
- setInnerHTML(this._inspector_peers_list, html.join(''));
},
- updateTrackersLists: function() {
- if (!$(this._inspector_trackers_list).is(':visible'))
- return;
+ removeSelectedTorrents: function() {
+ var torrents = this.getSelectedTorrents();
+ if (torrents.length)
+ this.promptToRemoveTorrents(torrents);
+ },
- var tr = this;
- var html = [ ];
- var na = 'N/A';
+ removeSelectedTorrentsAndData: function() {
var torrents = this.getSelectedTorrents();
+ if (torrents.length)
+ this.promptToRemoveTorrentsAndData(torrents);
+ },
- // By building up the HTML as as string, then have the browser
- // turn this into a DOM tree, this is a fast operation.
- for (var i=0, torrent; torrent=torrents[i]; ++i)
+ promptToRemoveTorrents:function(torrents)
+ {
+ if (torrents.length == 1)
{
- html.push ('<div class="inspector_group">');
+ var torrent = torrents[0];
+ 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);
+ }
+ else
+ {
+ var header = 'Remove ' + torrents.length + ' transfers?';
+ var message = 'Once removed, continuing the transfers will require the torrent files. Are you sure you want to remove them?';
+ dialog.confirm(header, message, 'Remove', 'transmission.removeTorrents', torrents);
+ }
+ },
- if (torrents.length > 1)
- html.push('<div class="inspector_torrent_label">', torrent.getName(), '</div>');
+ promptToRemoveTorrentsAndData:function(torrents)
+ {
+ if (torrents.length == 1)
+ {
+ var torrent = torrents[0],
+ 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);
+ }
+ else
+ {
+ var header = 'Remove ' + torrents.length + ' transfers and delete data?',
+ message = 'All data downloaded for these torrents will be deleted. Are you sure you want to remove them?';
+ dialog.confirm(header, message, 'Remove', 'transmission.removeTorrentsAndData', torrents);
+ }
+ },
- var tier = -1;
- var trackers = torrent.getTrackers();
- for (var j=0, tracker; tracker=trackers[j]; ++j)
- {
- if (tier != tracker.tier)
- {
- if (tier !== -1) // close previous tier
- html.push('</ul></div>');
-
- tier = tracker.tier;
+ removeTorrents: function(torrents) {
+ var torrent_ids = jQuery.map(torrents, function(t) { return t.getId(); });
+ var tr = this;
+ this.remote.removeTorrents(torrent_ids, function() { tr.refreshTorrents();});
+ },
- html.push('<div class="inspector_group_label">',
- 'Tier ', tier, '</div>',
- '<ul class="tier_list">');
- }
+ removeTorrentsAndData: function(torrents) {
+ this.remote.removeTorrentsAndData(torrents);
+ },
- var lastAnnounceStatusHash = tr.lastAnnounceStatus(tracker);
- var announceState = tr.announceState(tracker);
- var lastScrapeStatusHash = tr.lastScrapeStatus(tracker);
+ verifySelectedTorrents: function() {
+ this.verifyTorrents(this.getSelectedTorrents());
+ },
- // Display construction
- var parity = ((j+1) % 2 == 0 ? 'even' : 'odd');
- html.push('<li class="inspector_tracker_entry ', parity, '"><div class="tracker_host" title="', tracker.announce, '">',
- tracker.host, '</div>',
- '<div class="tracker_activity">',
- '<div>', lastAnnounceStatusHash['label'], ': ', lastAnnounceStatusHash['value'], '</div>',
- '<div>', announceState, '</div>',
- '<div>', lastScrapeStatusHash['label'], ': ', lastScrapeStatusHash['value'], '</div>',
- '</div><table class="tracker_stats">',
- '<tr><th>Seeders:</th><td>', (tracker.seederCount > -1 ? tracker.seederCount : na), '</td></tr>',
- '<tr><th>Leechers:</th><td>', (tracker.leecherCount > -1 ? tracker.leecherCount : na), '</td></tr>',
- '<tr><th>Downloads:</th><td>', (tracker.downloadCount > -1 ? tracker.downloadCount : na), '</td></tr>',
- '</table></li>');
- }
- if (tier !== -1) // close last tier
- html.push('</ul></div>');
+ reannounceSelectedTorrents: function() {
+ this.reannounceTorrents(this.getSelectedTorrents());
+ },
- html.push('</div>'); // inspector_group
- }
+ startSelectedTorrents: function(force) {
+ this.startTorrents(this.getSelectedTorrents(), force);
+ },
+ startAllTorrents: function() {
+ this.startTorrents(this.getAllTorrents(), false);
+ },
+ startTorrent: function(torrent) {
+ this.startTorrents([ torrent ], false);
+ },
+ startTorrents: function(torrents, force) {
+ 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); });
+ },
+ verifyTorrent: function(torrent) {
+ this.verifyTorrents([ torrent ]);
+ },
+ verifyTorrents: function(torrents) {
+ var tr = this;
+ var torrent_ids = jQuery.map(torrents, function(t) { return t.getId(); });
+ this.remote.verifyTorrents(torrent_ids, function() { tr.refreshTorrents(torrent_ids); });
+ },
- setInnerHTML(this._inspector_trackers_list, html.join(''));
+ reannounceTorrent: function(torrent) {
+ this.reannounceTorrents([ torrent ]);
+ },
+ reannounceTorrents: function(torrents) {
+ var tr = this;
+ var torrent_ids = jQuery.map(torrents, function(t) { return t.getId(); });
+ this.remote.reannounceTorrents(torrent_ids, function() { tr.refreshTorrents(torrent_ids); });
},
- lastAnnounceStatus: function(tracker) {
- var lastAnnounceLabel = 'Last Announce';
- var lastAnnounce = [ 'N/A' ];
- if (tracker.hasAnnounced) {
- var lastAnnounceTime = Transmission.fmt.timestamp(tracker.lastAnnounceTime);
- if (tracker.lastAnnounceSucceeded) {
- lastAnnounce = [ lastAnnounceTime, ' (got ', Transmission.fmt.plural(tracker.lastAnnouncePeerCount, 'peer'), ')' ];
- } else {
- lastAnnounceLabel = 'Announce error';
- lastAnnounce = [ (tracker.lastAnnounceResult ? (tracker.lastAnnounceResult + ' - ') : ''), lastAnnounceTime ];
- }
- }
- return { 'label':lastAnnounceLabel, 'value':lastAnnounce.join('') };
- },
-
- announceState: function(tracker) {
- var announceState = '';
- switch (tracker.announceState) {
- case Torrent._TrackerActive:
- announceState = 'Announce in progress';
- break;
- case Torrent._TrackerWaiting:
- var timeUntilAnnounce = tracker.nextAnnounceTime - ((new Date()).getTime() / 1000);
- if (timeUntilAnnounce < 0) {
- timeUntilAnnounce = 0;
- }
- announceState = 'Next announce in ' + Transmission.fmt.timeInterval(timeUntilAnnounce);
- break;
- case Torrent._TrackerQueued:
- announceState = 'Announce is queued';
- break;
- case Torrent._TrackerInactive:
- announceState = tracker.isBackup ?
- 'Tracker will be used as a backup' :
- 'Announce not scheduled';
- break;
- default:
- announceState = 'unknown announce state: ' + tracker.announceState;
- }
- return announceState;
+ stopSelectedTorrents: function() {
+ this.stopTorrents(this.getSelectedTorrents());
},
-
- lastScrapeStatus: function(tracker) {
- var lastScrapeLabel = 'Last Scrape';
- var lastScrape = 'N/A';
- if (tracker.hasScraped) {
- var lastScrapeTime = Transmission.fmt.timestamp(tracker.lastScrapeTime);
- if (tracker.lastScrapeSucceeded) {
- lastScrape = lastScrapeTime;
- } else {
- lastScrapeLabel = 'Scrape error';
- lastScrape = (tracker.lastScrapeResult ? tracker.lastScrapeResult + ' - ' : '') + lastScrapeTime;
- }
- }
- return {'label':lastScrapeLabel, 'value':lastScrape};
+ stopAllTorrents: function() {
+ this.stopTorrents(this.getAllTorrents());
},
-
- toggleInspector: function()
- {
- this.setInspectorVisible(!this[Prefs._ShowInspector]);
+ stopTorrent: function(torrent) {
+ this.stopTorrents([ torrent ]);
},
- setInspectorVisible: function(visible)
- {
- // we collect extra stats on torrents when they're in the inspector...
- clearInterval(this._periodic_inspector_refresh);
- delete this._periodic_inspector_refresh;
- if (visible) {
- var tr = this;
- this._periodic_inspector_refresh = setInterval(function() {tr.refreshInspectorTorrents(false);},2000);
- this.refreshInspectorTorrents(true);
- }
-
- // update the ui widgetry
- $('#torrent_inspector').toggle(visible);
- if (iPhone) {
- $('body').toggleClass('inspector_showing',visible);
- $('#inspector_close').toggle(visible);
- this.hideiPhoneAddressbar();
- } else {
- var w = visible ? $('#torrent_inspector').width() + 1 + 'px' : '0px';
- $('#torrent_container')[0].style.right = w;
- }
-
- setInnerHTML($('ul li#context_toggle_inspector')[0], (visible?'Hide':'Show')+' Inspector');
- this.setPref(Prefs._ShowInspector, visible);
- if (visible)
- this.updateInspector();
+ stopTorrents: function(torrents) {
+ var torrent_ids = jQuery.map(torrents, function(t) { return t.getId(); });
+ var tr = this;
+ this.remote.stopTorrents(torrent_ids, function() { tr.refreshTorrents(torrent_ids);});
},
-
- onTorrentChanged: function(ev)
- {
- this.refilterSoon();
-
- // if this torrent is in the inspector, refresh the inspector
- if (this[Prefs._ShowInspector])
- if (this.getSelectedTorrentIds().indexOf(ev.target.getId()) !== -1)
- this.updateInspector();
+ changeFileCommand: function(command, rows) {
+ this.remote.changeFileCommand(command, rows);
},
- updateFromTorrentGet: function(updates, removed_ids)
- {
- var new_ids = [];
-
- for (var i=0, o; o=updates[i]; ++i) {
- var t;
- var id = o.id;
- if ((t = this._torrents[id]))
- t.refresh(o);
- else {
- t = this._torrents[id] = new Torrent(o);
- $(t).bind('dataChanged',function(ev) {tr.onTorrentChanged(ev);});
- new_ids.push(id);
+ hideiPhoneAddressbar: function(timeInSeconds) {
+ if (iPhone) {
+ var delayLength = timeInSeconds ? timeInSeconds*1000 : 150;
+ // not currently supported on iPhone
+ if (/*document.body.scrollTop!=1 && */scroll_timeout==null) {
+ var tr = this;
+ scroll_timeout = setTimeout(function() {tr.doToolbarHide();}, delayLength);
}
}
-
- if (new_ids.length) {
- var tr = this;
- this.remote.getTorrentInitial(new_ids, function(a,b){tr.updateFromTorrentGet(a,b);});
- this.refilterSoon();
- }
-
- if (removed_ids) {
- this.deleteTorrents(removed_ids);
- this.refilterSoon();
- }
+ },
+ doToolbarHide: function() {
+ window.scrollTo(0,1);
+ scroll_timeout=null;
},
- refreshTorrents: function(ids) {
- if (!ids)
- ids = 'recently-active';
+ // Queue
+ moveTop: function() {
var tr = this;
- this.remote.getTorrentStats(ids, function(a,b){tr.updateFromTorrentGet(a,b);});
+ var torrent_ids = this.getSelectedTorrentIds();
+ this.remote.moveTorrentsToTop(torrent_ids, function() { tr.refreshTorrents(torrent_ids);});
},
- initializeAllTorrents: function() {
+ moveUp: function() {
var tr = this;
- this.remote.getTorrentInitial(null, function(a,b){tr.updateFromTorrentGet(a,b);});
+ var torrent_ids = this.getSelectedTorrentIds();
+ this.remote.moveTorrentsUp(torrent_ids, function() { tr.refreshTorrents(torrent_ids);});
},
- refreshMetadata: function(ids) {
+ moveDown: function() {
var tr = this;
- this.remote.getTorrentMetadata(ids, function(a,b){tr.updateFromTorrentGet(a,b);});
+ var torrent_ids = this.getSelectedTorrentIds();
+ this.remote.moveTorrentsDown(torrent_ids, function() { tr.refreshTorrents(torrent_ids);});
},
- refreshInspectorTorrents: function(full) {
+ moveBottom: function() {
var tr = this;
- var ids = tr.getSelectedTorrentIds();
- if (ids.length > 0)
- this.remote.getTorrentDetails(ids, full, function(a,b){tr.updateFromTorrentGet(a,b);});
+ var torrent_ids = this.getSelectedTorrentIds();
+ this.remote.moveTorrentsToBottom(torrent_ids, function() { tr.refreshTorrents(torrent_ids);});
},
- onRowClicked: function(ev, row)
- {
- // Prevents click carrying to parent element
- // which deselects all on click
- ev.stopPropagation();
- // but still hide the context menu if it is showing
- $('#jqContextMenu').hide();
-
- // 'Apple' button emulation on PC :
- // Need settable meta-key and ctrl-key variables for mac emulation
- var meta_key = ev.metaKey;
- if (ev.ctrlKey && navigator.appVersion.toLowerCase().indexOf("mac") == -1)
- meta_key = true;
-
- // Shift-Click - selects a range from the last-clicked row to this one
- if (iPhone) {
- if (row.isSelected())
- this.setInspectorVisible(true);
- this.setSelectedRow(row);
-
- } else if (ev.shiftKey) {
- this.selectRange(row);
- // Need to deselect any selected text
- window.focus();
-
- // Apple-Click, not selected
- } else if (!row.isSelected() && meta_key) {
- this.selectRow(row);
-
- // Regular Click, not selected
- } else if (!row.isSelected()) {
- this.setSelectedRow(row);
- // Apple-Click, selected
- } else if (row.isSelected() && meta_key) {
- this.deselectRow(row);
+ /***
+ ****
+ ***/
- // Regular Click, selected
- } else if (row.isSelected()) {
- this.setSelectedRow(row);
- }
+ onToggleRunningClicked: function(ev)
+ {
+ var torrent = ev.data.r.getTorrent();
- this._last_torrent_clicked = row.getTorrentId();
+ if (torrent.isStopped())
+ this.startTorrent(torrent);
+ else
+ this.stopTorrent(torrent);
},
- deleteTorrents: function(torrent_ids)
+ setEnabled: function(key, flag)
{
- if (torrent_ids && torrent_ids.length)
- {
- for (var i=0, id; id=torrent_ids[i]; ++i)
- delete this._torrents[id];
- this.refilter();
- }
+ $(key).toggleClass('disabled', !flag);
},
- updateStatusbar: function()
+ updateButtonStates: function()
{
- this.refreshFilterButton();
+ var showing_dialog = new RegExp("(prefs_showing|dialog_showing|open_showing)").test(document.body.className);
+ this._toolbar_buttons.toggleClass('disabled', showing_dialog);
- // up/down speed
- var u=0, d=0;
- var torrents = this.getAllTorrents();
- for (var i=0, row; row=torrents[i]; ++i) {
- u += row.getUploadSpeed();
- d += row.getDownloadSpeed();
- }
- setInnerHTML($('#statusbar #speed-up-label')[0], '↑ ' + Transmission.fmt.speedBps(u));
- setInnerHTML($('#statusbar #speed-dn-label')[0], '↓ ' + Transmission.fmt.speedBps(d));
- },
-
- /*
- * Select a torrent file to upload
- * FIXME
- */
- uploadTorrentFile: function(confirmed)
- {
- // Display the upload dialog
- if (! confirmed) {
- $('input#torrent_upload_file').attr('value', '');
- $('input#torrent_upload_url').attr('value', '');
- $('input#torrent_auto_start').attr('checked', $('#prefs_form #auto_start')[0].checked);
- $('#upload_container').show();
- $('#torrent_upload_url').focus();
- if (!iPhone && Safari3) {
- setTimeout("$('div#upload_container div.dialog_window').css('top', '0px');",10);
- }
-
- // Submit the upload form
- } else {
- var tr = this;
- var args = { };
- var paused = !$('#torrent_auto_start').is(':checked');
- if ('' != $('#torrent_upload_url').val()) {
- tr.remote.addTorrentByUrl($('#torrent_upload_url').val(), { paused: paused });
- } else {
- args.url = '../upload?paused=' + paused;
- args.type = 'POST';
- args.data = { 'X-Transmission-Session-Id' : tr.remote._token };
- args.dataType = 'xml';
- args.iframe = true;
- args.success = function() {
- tr.refreshTorrents();
- tr.togglePeriodicRefresh(true);
- };
- tr.togglePeriodicRefresh(false);
- $('#torrent_upload_form').ajaxSubmit(args);
- }
- }
- },
-
- removeSelectedTorrents: function() {
- var torrents = this.getSelectedTorrents();
- if (torrents.length)
- this.promptToRemoveTorrents(torrents);
- },
-
- removeSelectedTorrentsAndData: function() {
- var torrents = this.getSelectedTorrents();
- if (torrents.length)
- this.promptToRemoveTorrentsAndData(torrents);
- },
-
- promptToRemoveTorrents:function(torrents)
- {
- if (torrents.length == 1)
- {
- var torrent = torrents[0];
- 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);
- }
- else
- {
- var header = 'Remove ' + torrents.length + ' transfers?';
- var message = 'Once removed, continuing the transfers will require the torrent files. Are you sure you want to remove them?';
- dialog.confirm(header, message, 'Remove', 'transmission.removeTorrents', torrents);
- }
- },
-
- promptToRemoveTorrentsAndData:function(torrents)
- {
- if (torrents.length == 1)
- {
- var torrent = torrents[0],
- 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);
- }
- else
- {
- var header = 'Remove ' + torrents.length + ' transfers and delete data?',
- message = 'All data downloaded for these torrents will be deleted. Are you sure you want to remove them?';
- dialog.confirm(header, message, 'Remove', 'transmission.removeTorrentsAndData', torrents);
- }
- },
-
- removeTorrents: function(torrents) {
- var torrent_ids = jQuery.map(torrents, function(t) { return t.getId(); });
- var tr = this;
- this.remote.removeTorrents(torrent_ids, function() { tr.refreshTorrents();});
- },
-
- removeTorrentsAndData: function(torrents) {
- this.remote.removeTorrentsAndData(torrents);
- },
-
- verifySelectedTorrents: function() {
- this.verifyTorrents(this.getSelectedTorrents());
- },
-
- reannounceSelectedTorrents: function() {
- this.reannounceTorrents(this.getSelectedTorrents());
- },
-
- startSelectedTorrents: function(force) {
- this.startTorrents(this.getSelectedTorrents(), force);
- },
- startAllTorrents: function() {
- this.startTorrents(this.getAllTorrents(), false);
- },
- startTorrent: function(torrent) {
- this.startTorrents([ torrent ], false);
- },
- startTorrents: function(torrents, force) {
- 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); });
- },
- verifyTorrent: function(torrent) {
- this.verifyTorrents([ torrent ]);
- },
- verifyTorrents: function(torrents) {
- var tr = this;
- var torrent_ids = jQuery.map(torrents, function(t) { return t.getId(); });
- this.remote.verifyTorrents(torrent_ids, function() { tr.refreshTorrents(torrent_ids); });
- },
-
- reannounceTorrent: function(torrent) {
- this.reannounceTorrents([ torrent ]);
- },
- reannounceTorrents: function(torrents) {
- var tr = this;
- var torrent_ids = jQuery.map(torrents, function(t) { return t.getId(); });
- this.remote.reannounceTorrents(torrent_ids, function() { tr.refreshTorrents(torrent_ids); });
- },
-
- stopSelectedTorrents: function() {
- this.stopTorrents(this.getSelectedTorrents());
- },
- stopAllTorrents: function() {
- this.stopTorrents(this.getAllTorrents());
- },
- stopTorrent: function(torrent) {
- this.stopTorrents([ torrent ]);
- },
- stopTorrents: function(torrents) {
- var torrent_ids = jQuery.map(torrents, function(t) { return t.getId(); });
- var tr = this;
- this.remote.stopTorrents(torrent_ids, function() { tr.refreshTorrents(torrent_ids);});
- },
- changeFileCommand: function(command, rows) {
- this.remote.changeFileCommand(command, rows);
- },
-
- hideiPhoneAddressbar: function(timeInSeconds) {
- if (iPhone) {
- var delayLength = timeInSeconds ? timeInSeconds*1000 : 150;
- // not currently supported on iPhone
- if (/*document.body.scrollTop!=1 && */scroll_timeout==null) {
- var tr = this;
- scroll_timeout = setTimeout(function() {tr.doToolbarHide();}, delayLength);
- }
- }
- },
- doToolbarHide: function() {
- window.scrollTo(0,1);
- scroll_timeout=null;
- },
-
- // Queue
- moveTop: function() {
- var tr = this;
- var torrent_ids = this.getSelectedTorrentIds();
- this.remote.moveTorrentsToTop(torrent_ids, function() { tr.refreshTorrents(torrent_ids);});
- },
- moveUp: function() {
- var tr = this;
- var torrent_ids = this.getSelectedTorrentIds();
- this.remote.moveTorrentsUp(torrent_ids, function() { tr.refreshTorrents(torrent_ids);});
- },
- moveDown: function() {
- var tr = this;
- var torrent_ids = this.getSelectedTorrentIds();
- this.remote.moveTorrentsDown(torrent_ids, function() { tr.refreshTorrents(torrent_ids);});
- },
- moveBottom: function() {
- var tr = this;
- var torrent_ids = this.getSelectedTorrentIds();
- this.remote.moveTorrentsToBottom(torrent_ids, function() { tr.refreshTorrents(torrent_ids);});
- },
-
-
- /***
- ****
- ***/
-
- onToggleRunningClicked: function(ev)
- {
- var torrent = ev.data.r.getTorrent();
-
- if (torrent.isStopped())
- this.startTorrent(torrent);
- else
- this.stopTorrent(torrent);
- },
-
- setEnabled: function(key, flag)
- {
- $(key).toggleClass('disabled', !flag);
- },
-
- updateButtonStates: function()
- {
- var showing_dialog = new RegExp("(prefs_showing|dialog_showing|open_showing)").test(document.body.className);
- this._toolbar_buttons.toggleClass('disabled', showing_dialog);
-
- if (!showing_dialog)
- {
- var haveSelection = false;
- var haveActive = false;
- var haveActiveSelection = false;
- var havePaused = false;
- var havePausedSelection = false;
+ if (!showing_dialog)
+ {
+ var haveSelection = false;
+ var haveActive = false;
+ var haveActiveSelection = false;
+ var havePaused = false;
+ var havePausedSelection = false;
for (var i=0, row; row=this._rows[i]; ++i) {
var isStopped = row.getTorrent().isStopped();
}
},
+ /****
+ *****
+ ***** INSPECTOR
+ *****
+ ****/
+
+ inspectorTabClicked: function(ev, tab)
+ {
+ if (iPhone) ev.stopPropagation();
+
+ // select this tab and deselect the others
+ $(tab).addClass('selected').siblings().removeClass('selected');
+
+ // show this tab and hide the others
+ $('#'+tab.id+'_container').show().siblings('.inspector_container').hide();
+
+ this.hideiPhoneAddressbar();
+ this.updatePeersLists();
+ this.updateTrackersLists();
+ this.updateFileList();
+ },
+ /*
+ * Update the inspector with the latest data for the selected torrents
+ */
+ updateInspector: function()
+ {
+ if (!this[Prefs._ShowInspector])
+ return;
+
+ var torrents = this.getSelectedTorrents();
+ if (!torrents.length && iPhone) {
+ this.setInspectorVisible(false);
+ return;
+ }
+
+ var creator = 'N/A';
+ var comment = 'N/A';
+ var download_dir = 'N/A';
+ var date_created = 'N/A';
+ var error = 'None';
+ var hash = 'N/A';
+ var have_public = false;
+ var have_private = false;
+ var name;
+ var sizeWhenDone = 0;
+ var sizeDone = 0;
+ var total_completed = 0;
+ var total_download = 0;
+ var total_download_peers = 0;
+ var total_download_speed = 0;
+ var total_availability = 0;
+ var total_size = 0;
+ var total_state = [ ];
+ var pieces = 'N/A';
+ var total_upload = 0;
+ var total_upload_peers = 0;
+ var total_upload_speed = 0;
+ var total_verified = 0;
+ var na = 'N/A';
+ var tab = this._inspector._info_tab;
+
+ $("#torrent_inspector_size, .inspector_row div").css('color', '#222');
+
+ if (torrents.length == 0)
+ {
+ setInnerHTML(tab.name, 'No Selection');
+ setInnerHTML(tab.size, na);
+ setInnerHTML(tab.pieces, na);
+ setInnerHTML(tab.hash, na);
+ setInnerHTML(tab.state, na);
+ setInnerHTML(tab.download_speed, na);
+ setInnerHTML(tab.upload_speed, na);
+ setInnerHTML(tab.uploaded, na);
+ setInnerHTML(tab.downloaded, na);
+ setInnerHTML(tab.availability, na);
+ setInnerHTML(tab.ratio, na);
+ setInnerHTML(tab.have, na);
+ setInnerHTML(tab.upload_to, na);
+ setInnerHTML(tab.download_from, na);
+ setInnerHTML(tab.secure, na);
+ setInnerHTML(tab.creator_date, na);
+ setInnerHTML(tab.progress, na);
+ setInnerHTML(tab.comment, na);
+ setInnerHTML(tab.creator, na);
+ setInnerHTML(tab.download_dir, na);
+ setInnerHTML(tab.error, na);
+ this.updateFileList();
+ this.updatePeersLists();
+ this.updateTrackersLists();
+ $("#torrent_inspector_size, .inspector_row > div:contains('N/A')").css('color', '#666');
+ return;
+ }
+
+ name = torrents.length == 1
+ ? 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 ((text = t.getComment()))
+ comment = text;
+ if ((text = t.getCreator()))
+ creator = text;
+ if ((text = t.getDownloadDir()))
+ download_dir = text;
+
+ 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) {
+ var l = t.getLeftUntilDone();
+ var d = t.getSizeWhenDone();
+ sizeWhenDone += d;
+ sizeDone += d - l;
+ 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 - l + t.getDesiredAvailable();
+
+ var s = t.getStateString();
+ if (total_state.indexOf(s) == -1)
+ total_state.push(s);
+
+ if (t.getPrivateFlag())
+ have_private = true;
+ else
+ have_public = true;
+ }
+
+ var private_string = '';
+ var fmt = Transmission.fmt;
+ if (have_private && have_public) private_string = 'Mixed';
+ else if (have_private) private_string = 'Private Torrent';
+ else if (have_public) private_string = 'Public Torrent';
+
+ setInnerHTML(tab.name, name);
+ setInnerHTML(tab.size, torrents.length ? fmt.size(total_size) : na);
+ setInnerHTML(tab.pieces, pieces);
+ setInnerHTML(tab.hash, hash);
+ setInnerHTML(tab.state, total_state.join('/'));
+ setInnerHTML(tab.download_speed, torrents.length ? fmt.speedBps(total_download_speed) : na);
+ setInnerHTML(tab.upload_speed, torrents.length ? fmt.speedBps(total_upload_speed) : na);
+ setInnerHTML(tab.uploaded, torrents.length ? fmt.size(total_upload) : na);
+ setInnerHTML(tab.downloaded, torrents.length ? fmt.size(total_download) : na);
+ setInnerHTML(tab.availability, torrents.length ? fmt.percentString(Math.ratio(total_availability*100, sizeWhenDone)) + '%' : na);
+ setInnerHTML(tab.ratio, torrents.length ? fmt.ratioString(Math.ratio(total_upload, total_download)) : na);
+ setInnerHTML(tab.have, torrents.length ? fmt.size(total_completed) + ' (' + fmt.size(total_verified) + ' verified)' : na);
+ setInnerHTML(tab.upload_to, torrents.length ? total_upload_peers : na);
+ setInnerHTML(tab.download_from, torrents.length ? total_download_peers : na);
+ setInnerHTML(tab.secure, private_string);
+ setInnerHTML(tab.creator_date, date_created);
+ setInnerHTML(tab.progress, torrents.length ? fmt.percentString(Math.ratio(sizeDone*100, sizeWhenDone)) + '%' : na);
+ setInnerHTML(tab.comment, comment);
+ setInnerHTML(tab.creator, creator);
+ setInnerHTML(tab.download_dir, download_dir);
+ setInnerHTML(tab.error, error);
+
+ this.updatePeersLists();
+ this.updateTrackersLists();
+ $(".inspector_row > div:contains('N/A')").css('color', '#666');
+ this.updateFileList();
+ },
+
+ onFileWantedToggled: function(row, want) {
+ var command = want ? 'files-wanted' : 'files-unwanted';
+ this.changeFileCommand(command, [ row ]);
+ },
+ onFilePriorityToggled: function(row, priority) {
+ var command;
+ switch(priority) {
+ case -1: command = 'priority-low'; break;
+ case 1: command = 'priority-high'; break;
+ default: command = 'priority-normal'; break;
+ }
+ this.changeFileCommand(command, [ row ]);
+ },
+ clearFileList: function()
+ {
+ $(this._inspector_file_list).empty();
+ delete this._file_torrent;
+ delete this._file_rows;
+ },
+ updateFileList: function()
+ {
+ if (!$(this._inspector_file_list).is(':visible'))
+ return;
+
+ var sel = this.getSelectedTorrents();
+ if (sel.length !== 1) {
+ this.clearFileList();
+ return;
+ }
+
+ var torrent = sel[0];
+ if (torrent === this._files_torrent)
+ if(torrent.getFileCount() === (this._files ? this._files.length: 0))
+ return;
+
+ // build the file list
+ this.clearFileList();
+ this._file_torrent = torrent;
+ var n = torrent.getFileCount();
+ this._file_rows = [];
+ var fragment = document.createDocumentFragment();
+ var tr = this;
+ for (var i=0; i<n; ++i) {
+ var row = this._file_rows[i] = new FileRow(torrent, i);
+ fragment.appendChild(row.getElement());
+ $(row).bind('wantedToggled',function(e,row,want) {tr.onFileWantedToggled(row,want);});
+ $(row).bind('priorityToggled',function(e,row,priority) {tr.onFilePriorityToggled(row,priority);});
+ }
+ this._inspector_file_list.appendChild(fragment);
+ },
+
+ updatePeersLists: function()
+ {
+ if (!$(this._inspector_peers_list).is(':visible'))
+ return;
+
+ var html = [ ];
+ var fmt = Transmission.fmt;
+ var torrents = this.getSelectedTorrents();
+
+ for (var k=0, torrent; torrent=torrents[k]; ++k) {
+ var peers = torrent.getPeers();
+ html.push('<div class="inspector_group">');
+ if (torrents.length > 1) {
+ html.push('<div class="inspector_torrent_label">', torrent.getName(), '</div>');
+ }
+ if (!peers || !peers.length) {
+ html.push('<br></div>'); // firefox won't paint the top border if the div is empty
+ continue;
+ }
+ html.push('<table class="peer_list">',
+ '<tr class="inspector_peer_entry even">',
+ '<th class="encryptedCol"></th>',
+ '<th class="upCol">Up</th>',
+ '<th class="downCol">Down</th>',
+ '<th class="percentCol">%</th>',
+ '<th class="statusCol">Status</th>',
+ '<th class="addressCol">Address</th>',
+ '<th class="clientCol">Client</th>',
+ '</tr>');
+ for (var i=0, peer; peer=peers[i]; ++i) {
+ var parity = ((i+1) % 2 == 0 ? 'even' : 'odd');
+ html.push('<tr class="inspector_peer_entry ', parity, '">',
+ '<td>', (peer.isEncrypted ? '<img src="images/graphics/lock_icon.png" alt="Encrypted"/>' : ''), '</td>',
+ '<td>', (peer.rateToPeer ? fmt.speedBps(peer.rateToPeer) : ''), '</td>',
+ '<td>', (peer.rateToClient ? fmt.speedBps(peer.rateToClient) : ''), '</td>',
+ '<td class="percentCol">', Math.floor(peer.progress*100), '%', '</td>',
+ '<td>', fmt.peerStatus(peer.flagStr), '</td>',
+ '<td>', peer.address, '</td>',
+ '<td class="clientCol">', peer.clientName, '</td>',
+ '</tr>');
+ }
+ html.push('</table></div>');
+ }
+
+ setInnerHTML(this._inspector_peers_list, html.join(''));
+ },
+
+ updateTrackersLists: function() {
+ if (!$(this._inspector_trackers_list).is(':visible'))
+ return;
+
+ var tr = this;
+ var html = [ ];
+ var na = 'N/A';
+ var torrents = this.getSelectedTorrents();
+
+ // By building up the HTML as as string, then have the browser
+ // turn this into a DOM tree, this is a fast operation.
+ for (var i=0, torrent; torrent=torrents[i]; ++i)
+ {
+ html.push ('<div class="inspector_group">');
+
+ if (torrents.length > 1)
+ html.push('<div class="inspector_torrent_label">', torrent.getName(), '</div>');
+
+ var tier = -1;
+ var trackers = torrent.getTrackers();
+ for (var j=0, tracker; tracker=trackers[j]; ++j)
+ {
+ if (tier != tracker.tier)
+ {
+ if (tier !== -1) // close previous tier
+ html.push('</ul></div>');
+
+ tier = tracker.tier;
+
+ html.push('<div class="inspector_group_label">',
+ 'Tier ', tier, '</div>',
+ '<ul class="tier_list">');
+ }
+
+ var lastAnnounceStatusHash = tr.lastAnnounceStatus(tracker);
+ var announceState = tr.announceState(tracker);
+ var lastScrapeStatusHash = tr.lastScrapeStatus(tracker);
+
+ // Display construction
+ var parity = ((j+1) % 2 == 0 ? 'even' : 'odd');
+ html.push('<li class="inspector_tracker_entry ', parity, '"><div class="tracker_host" title="', tracker.announce, '">',
+ tracker.host, '</div>',
+ '<div class="tracker_activity">',
+ '<div>', lastAnnounceStatusHash['label'], ': ', lastAnnounceStatusHash['value'], '</div>',
+ '<div>', announceState, '</div>',
+ '<div>', lastScrapeStatusHash['label'], ': ', lastScrapeStatusHash['value'], '</div>',
+ '</div><table class="tracker_stats">',
+ '<tr><th>Seeders:</th><td>', (tracker.seederCount > -1 ? tracker.seederCount : na), '</td></tr>',
+ '<tr><th>Leechers:</th><td>', (tracker.leecherCount > -1 ? tracker.leecherCount : na), '</td></tr>',
+ '<tr><th>Downloads:</th><td>', (tracker.downloadCount > -1 ? tracker.downloadCount : na), '</td></tr>',
+ '</table></li>');
+ }
+ if (tier !== -1) // close last tier
+ html.push('</ul></div>');
+
+ html.push('</div>'); // inspector_group
+ }
+
+ setInnerHTML(this._inspector_trackers_list, html.join(''));
+ },
+
+ lastAnnounceStatus: function(tracker) {
+ var lastAnnounceLabel = 'Last Announce';
+ var lastAnnounce = [ 'N/A' ];
+ if (tracker.hasAnnounced) {
+ var lastAnnounceTime = Transmission.fmt.timestamp(tracker.lastAnnounceTime);
+ if (tracker.lastAnnounceSucceeded) {
+ lastAnnounce = [ lastAnnounceTime, ' (got ', Transmission.fmt.plural(tracker.lastAnnouncePeerCount, 'peer'), ')' ];
+ } else {
+ lastAnnounceLabel = 'Announce error';
+ lastAnnounce = [ (tracker.lastAnnounceResult ? (tracker.lastAnnounceResult + ' - ') : ''), lastAnnounceTime ];
+ }
+ }
+ return { 'label':lastAnnounceLabel, 'value':lastAnnounce.join('') };
+ },
+
+ announceState: function(tracker) {
+ var announceState = '';
+ switch (tracker.announceState) {
+ case Torrent._TrackerActive:
+ announceState = 'Announce in progress';
+ break;
+ case Torrent._TrackerWaiting:
+ var timeUntilAnnounce = tracker.nextAnnounceTime - ((new Date()).getTime() / 1000);
+ if (timeUntilAnnounce < 0) {
+ timeUntilAnnounce = 0;
+ }
+ announceState = 'Next announce in ' + Transmission.fmt.timeInterval(timeUntilAnnounce);
+ break;
+ case Torrent._TrackerQueued:
+ announceState = 'Announce is queued';
+ break;
+ case Torrent._TrackerInactive:
+ announceState = tracker.isBackup ?
+ 'Tracker will be used as a backup' :
+ 'Announce not scheduled';
+ break;
+ default:
+ announceState = 'unknown announce state: ' + tracker.announceState;
+ }
+ return announceState;
+ },
+
+ lastScrapeStatus: function(tracker) {
+ var lastScrapeLabel = 'Last Scrape';
+ var lastScrape = 'N/A';
+ if (tracker.hasScraped) {
+ var lastScrapeTime = Transmission.fmt.timestamp(tracker.lastScrapeTime);
+ if (tracker.lastScrapeSucceeded) {
+ lastScrape = lastScrapeTime;
+ } else {
+ lastScrapeLabel = 'Scrape error';
+ lastScrape = (tracker.lastScrapeResult ? tracker.lastScrapeResult + ' - ' : '') + lastScrapeTime;
+ }
+ }
+ return {'label':lastScrapeLabel, 'value':lastScrape};
+ },
+
+ toggleInspector: function()
+ {
+ this.setInspectorVisible(!this[Prefs._ShowInspector]);
+ },
+ setInspectorVisible: function(visible)
+ {
+ // we collect extra stats on torrents when they're in the inspector...
+ clearInterval(this._periodic_inspector_refresh);
+ delete this._periodic_inspector_refresh;
+ if (visible) {
+ var tr = this;
+ this._periodic_inspector_refresh = setInterval(function() {tr.refreshInspectorTorrents(false);},2000);
+ this.refreshInspectorTorrents(true);
+ }
+
+ // update the ui widgetry
+ $('#torrent_inspector').toggle(visible);
+ if (iPhone) {
+ $('body').toggleClass('inspector_showing',visible);
+ $('#inspector_close').toggle(visible);
+ this.hideiPhoneAddressbar();
+ } else {
+ var w = visible ? $('#torrent_inspector').width() + 1 + 'px' : '0px';
+ $('#torrent_container')[0].style.right = w;
+ }
+
+ setInnerHTML($('ul li#context_toggle_inspector')[0], (visible?'Hide':'Show')+' Inspector');
+ this.setPref(Prefs._ShowInspector, visible);
+ if (visible)
+ this.updateInspector();
+ },
+
/****
*****
***** FILTER