transmission/web/javascript/torrent-row.js

452 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Copyright © Mnemosyne LLC
*
* This file is licensed under the GPLv2.
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*/
function TorrentRendererHelper() {}
TorrentRendererHelper.getProgressInfo = function (controller, t) {
let pct, extra;
const s = t.getStatus();
const seed_ratio_limit = t.seedRatioLimit(controller);
if (t.needsMetaData()) {
pct = t.getMetadataPercentComplete() * 100;
} else if (!t.isDone()) {
pct = Math.round(t.getPercentDone() * 100);
} else if (seed_ratio_limit > 0 && t.isSeeding()) {
// don't split up the bar if paused or queued
pct = Math.round((t.getUploadRatio() * 100) / seed_ratio_limit);
} else {
pct = 100;
}
if (s === Torrent._StatusStopped) {
extra = 'paused';
} else if (s === Torrent._StatusDownloadWait) {
extra = 'leeching queued';
} else if (t.needsMetaData()) {
extra = 'magnet';
} else if (s === Torrent._StatusDownload) {
extra = 'leeching';
} else if (s === Torrent._StatusSeedWait) {
extra = 'seeding queued';
} else if (s === Torrent._StatusSeed) {
extra = 'seeding';
} else {
extra = '';
}
return {
percent: pct,
complete: ['torrent_progress_bar', 'complete', extra].join(' '),
incomplete: ['torrent_progress_bar', 'incomplete', extra].join(' '),
};
};
TorrentRendererHelper.createProgressbar = function (classes) {
let complete, incomplete, progressbar;
complete = document.createElement('div');
complete.className = 'torrent_progress_bar complete';
incomplete = document.createElement('div');
incomplete.className = 'torrent_progress_bar incomplete';
progressbar = document.createElement('div');
progressbar.className = 'torrent_progress_bar_container ' + classes;
progressbar.appendChild(complete);
progressbar.appendChild(incomplete);
return {
element: progressbar,
complete: complete,
incomplete: incomplete,
};
};
TorrentRendererHelper.renderProgressbar = function (controller, t, progressbar) {
let e, style, width, display;
const info = TorrentRendererHelper.getProgressInfo(controller, t);
// update the complete progressbar
e = progressbar.complete;
style = e.style;
width = '' + info.percent + '%';
display = info.percent > 0 ? 'block' : 'none';
if (style.width !== width || style.display !== display) {
$(e).css({
width: '' + info.percent + '%',
display: display,
});
}
if (e.className !== info.complete) {
e.className = info.complete;
}
// update the incomplete progressbar
e = progressbar.incomplete;
display = info.percent < 100 ? 'block' : 'none';
if (e.style.display !== display) {
e.style.display = display;
}
if (e.className !== info.incomplete) {
e.className = info.incomplete;
}
};
TorrentRendererHelper.formatUL = function (t) {
return '▲' + Transmission.fmt.speedBps(t.getUploadSpeed());
};
TorrentRendererHelper.formatDL = function (t) {
return '▼' + Transmission.fmt.speedBps(t.getDownloadSpeed());
};
TorrentRendererHelper.formatETA = function (t) {
const eta = t.getETA();
if (eta < 0 || eta >= 999 * 60 * 60) {
return '';
}
return 'ETA: ' + Transmission.fmt.timeInterval(eta);
};
/****
*****
*****
****/
function TorrentRendererFull() {}
TorrentRendererFull.prototype = {
createRow: function () {
let root, name, peers, progressbar, details, image, button;
root = document.createElement('li');
root.className = 'torrent';
name = document.createElement('div');
name.className = 'torrent_name';
peers = document.createElement('div');
peers.className = 'torrent_peer_details';
progressbar = TorrentRendererHelper.createProgressbar('full');
details = document.createElement('div');
details.className = 'torrent_progress_details';
image = document.createElement('div');
button = document.createElement('a');
button.appendChild(image);
root.appendChild(name);
root.appendChild(peers);
root.appendChild(button);
root.appendChild(progressbar.element);
root.appendChild(details);
root._name_container = name;
root._peer_details_container = peers;
root._progress_details_container = details;
root._progressbar = progressbar;
root._pause_resume_button_image = image;
root._toggle_running_button = button;
return root;
},
getPeerDetails: function (t) {
let err,
peer_count,
webseed_count,
fmt = Transmission.fmt;
if ((err = t.getErrorMessage())) {
return err;
}
if (t.isDownloading()) {
peer_count = t.getPeersConnected();
webseed_count = t.getWebseedsSendingToUs();
if (webseed_count && peer_count) {
// Downloading from 2 of 3 peer(s) and 2 webseed(s)
return [
'Downloading from',
t.getPeersSendingToUs(),
'of',
fmt.countString('peer', 'peers', peer_count),
'and',
fmt.countString('web seed', 'web seeds', webseed_count),
'',
TorrentRendererHelper.formatDL(t),
TorrentRendererHelper.formatUL(t),
].join(' ');
} else if (webseed_count) {
// Downloading from 2 webseed(s)
return [
'Downloading from',
fmt.countString('web seed', 'web seeds', webseed_count),
'',
TorrentRendererHelper.formatDL(t),
TorrentRendererHelper.formatUL(t),
].join(' ');
} else {
// Downloading from 2 of 3 peer(s)
return [
'Downloading from',
t.getPeersSendingToUs(),
'of',
fmt.countString('peer', 'peers', peer_count),
'',
TorrentRendererHelper.formatDL(t),
TorrentRendererHelper.formatUL(t),
].join(' ');
}
}
if (t.isSeeding()) {
return [
'Seeding to',
t.getPeersGettingFromUs(),
'of',
fmt.countString('peer', 'peers', t.getPeersConnected()),
'-',
TorrentRendererHelper.formatUL(t),
].join(' ');
}
if (t.isChecking()) {
return [
'Verifying local data (',
Transmission.fmt.percentString(100.0 * t.getRecheckProgress()),
'% tested)',
].join('');
}
return t.getStateString();
},
getProgressDetails: function (controller, t) {
if (t.needsMetaData()) {
let MetaDataStatus = 'retrieving';
if (t.isStopped()) {
MetaDataStatus = 'needs';
}
const percent = 100 * t.getMetadataPercentComplete();
return [
'Magnetized transfer - ' + MetaDataStatus + ' metadata (',
Transmission.fmt.percentString(percent),
'%)',
].join('');
}
let c;
const sizeWhenDone = t.getSizeWhenDone();
const totalSize = t.getTotalSize();
const is_done = t.isDone() || t.isSeeding();
if (is_done) {
if (totalSize === sizeWhenDone) {
// seed: '698.05 MiB'
c = [Transmission.fmt.size(totalSize)];
} else {
// partial seed: '127.21 MiB of 698.05 MiB (18.2%)'
c = [
Transmission.fmt.size(sizeWhenDone),
' of ',
Transmission.fmt.size(t.getTotalSize()),
' (',
t.getPercentDoneStr(),
'%)',
];
}
// append UL stats: ', uploaded 8.59 GiB (Ratio: 12.3)'
c.push(
', uploaded ',
Transmission.fmt.size(t.getUploadedEver()),
' (Ratio ',
Transmission.fmt.ratioString(t.getUploadRatio()),
')'
);
} else {
// not done yet
c = [
Transmission.fmt.size(sizeWhenDone - t.getLeftUntilDone()),
' of ',
Transmission.fmt.size(sizeWhenDone),
' (',
t.getPercentDoneStr(),
'%)',
];
}
// maybe append eta
if (!t.isStopped() && (!is_done || t.seedRatioLimit(controller) > 0)) {
c.push(' - ');
const eta = t.getETA();
if (eta < 0 || eta >= 999 * 60 * 60 /* arbitrary */) {
c.push('remaining time unknown');
} else {
c.push(Transmission.fmt.timeInterval(t.getETA()), ' remaining');
}
}
return c.join('');
},
render: function (controller, t, root) {
// name
setTextContent(root._name_container, t.getName());
// progressbar
TorrentRendererHelper.renderProgressbar(controller, t, root._progressbar);
// peer details
const has_error = t.getError() !== Torrent._ErrNone;
let e = root._peer_details_container;
$(e).toggleClass('error', has_error);
setTextContent(e, this.getPeerDetails(t));
// progress details
e = root._progress_details_container;
setTextContent(e, this.getProgressDetails(controller, t));
// pause/resume button
const is_stopped = t.isStopped();
e = root._pause_resume_button_image;
e.alt = is_stopped ? 'Resume' : 'Pause';
e.className = is_stopped ? 'torrent_resume' : 'torrent_pause';
},
};
/****
*****
*****
****/
function TorrentRendererCompact() {}
TorrentRendererCompact.prototype = {
createRow: function () {
let progressbar, details, name, root;
progressbar = TorrentRendererHelper.createProgressbar('compact');
details = document.createElement('div');
details.className = 'torrent_peer_details compact';
name = document.createElement('div');
name.className = 'torrent_name compact';
root = document.createElement('li');
root.appendChild(progressbar.element);
root.appendChild(details);
root.appendChild(name);
root.className = 'torrent compact';
root._progressbar = progressbar;
root._details_container = details;
root._name_container = name;
return root;
},
getPeerDetails: function (t) {
let c;
if ((c = t.getErrorMessage())) {
return c;
}
if (t.isDownloading()) {
const have_dn = t.getDownloadSpeed() > 0;
const have_up = t.getUploadSpeed() > 0;
if (!have_up && !have_dn) {
return 'Idle';
}
let s = '';
if (!isMobileDevice) {
s = TorrentRendererHelper.formatETA(t) + ' ';
}
if (have_dn) {
s += TorrentRendererHelper.formatDL(t);
}
if (have_dn && have_up) {
s += ' ';
}
if (have_up) {
s += TorrentRendererHelper.formatUL(t);
}
return s;
}
if (t.isSeeding()) {
return [
'Ratio: ',
Transmission.fmt.ratioString(t.getUploadRatio()),
', ',
TorrentRendererHelper.formatUL(t),
].join('');
}
return t.getStateString();
},
render: function (controller, t, root) {
// name
const is_stopped = t.isStopped();
let e = root._name_container;
$(e).toggleClass('paused', is_stopped);
setTextContent(e, t.getName());
// peer details
const has_error = t.getError() !== Torrent._ErrNone;
e = root._details_container;
$(e).toggleClass('error', has_error);
setTextContent(e, this.getPeerDetails(t));
// progressbar
TorrentRendererHelper.renderProgressbar(controller, t, root._progressbar);
},
};
/****
*****
*****
****/
function TorrentRow(view, controller, torrent) {
this.initialize(view, controller, torrent);
}
TorrentRow.prototype = {
initialize: function (view, controller, torrent) {
const row = this;
this._view = view;
this._torrent = torrent;
this._element = view.createRow();
this.render(controller);
$(this._torrent).bind('dataChanged.torrentRowListener', function () {
row.render(controller);
});
},
getElement: function () {
return this._element;
},
render: function (controller) {
const tor = this.getTorrent();
if (tor) {
this._view.render(controller, tor, this.getElement());
}
},
isSelected: function () {
return this.getElement().className.indexOf('selected') !== -1;
},
getTorrent: function () {
return this._torrent;
},
getTorrentId: function () {
return this.getTorrent().getId();
},
};