#6089: Beautified JavaScript (patch by skybon)

This commit is contained in:
Mike Gelfand 2016-03-10 19:05:13 +00:00
parent 0fd932eaa5
commit 5569efc3d4
12 changed files with 4725 additions and 4551 deletions

9
.jsbeautifyrc Normal file
View File

@ -0,0 +1,9 @@
{
"indent_size": 4,
"indent_char": " ",
"indent_level": 0,
"indent_with_tabs": false,
"preserve_newlines": true,
"max_preserve_newlines": 2,
"jslint_happy": true
}

View File

@ -10,91 +10,110 @@ var transmission,
isMobileDevice = RegExp("(iPhone|iPod|Android)").test(navigator.userAgent),
scroll_timeout;
if (!Array.indexOf){
Array.prototype.indexOf = function(obj){
var i, len;
for (i=0, len=this.length; i<len; i++)
if (this[i]==obj)
return i;
return -1;
}
}
if (!Array.indexOf) {
Array.prototype.indexOf = function (obj) {
var i, len;
for (i = 0, len = this.length; i < len; i++) {
if (this[i] == obj) {
return i;
};
};
return -1;
};
};
// http://forum.jquery.com/topic/combining-ui-dialog-and-tabs
$.fn.tabbedDialog = function (dialog_opts) {
this.tabs({selected: 0});
this.dialog(dialog_opts);
this.find('.ui-tab-dialog-close').append(this.parent().find('.ui-dialog-titlebar-close'));
this.find('.ui-tab-dialog-close').css({'position':'absolute','right':'0', 'top':'16px'});
this.find('.ui-tab-dialog-close > a').css({'float':'none','padding':'0'});
var tabul = this.find('ul:first');
this.parent().addClass('ui-tabs').prepend(tabul).draggable('option','handle',tabul);
this.siblings('.ui-dialog-titlebar').remove();
tabul.addClass('ui-dialog-titlebar');
this.tabs({
selected: 0
});
this.dialog(dialog_opts);
this.find('.ui-tab-dialog-close').append(this.parent().find('.ui-dialog-titlebar-close'));
this.find('.ui-tab-dialog-close').css({
'position': 'absolute',
'right': '0',
'top': '16px'
});
this.find('.ui-tab-dialog-close > a').css({
'float': 'none',
'padding': '0'
});
var tabul = this.find('ul:first');
this.parent().addClass('ui-tabs').prepend(tabul).draggable('option', 'handle', tabul);
this.siblings('.ui-dialog-titlebar').remove();
tabul.addClass('ui-dialog-titlebar');
}
$(document).ready(function() {
$(document).ready(function () {
// IE8 and below dont support ES5 Date.now()
if (!Date.now) {
Date.now = function() {
return +new Date();
};
}
// IE8 and below dont support ES5 Date.now()
if (!Date.now) {
Date.now = function () {
return +new Date();
};
};
// IE specific fixes here
if ($.browser.msie) {
try {
document.execCommand("BackgroundImageCache", false, true);
} catch(err) {}
$('.dialog_container').css('height',$(window).height()+'px');
}
// IE specific fixes here
if ($.browser.msie) {
try {
document.execCommand("BackgroundImageCache", false, true);
} catch (err) {};
$('.dialog_container').css('height', $(window).height() + 'px');
};
if ($.browser.safari) {
// Move search field's margin down for the styled input
$('#torrent_search').css('margin-top', 3);
}
if (isMobileDevice){
window.onload = function(){ setTimeout(function() { window.scrollTo(0,1); },500); };
window.onorientationchange = function(){ setTimeout(function() { window.scrollTo(0,1); },100); };
if (window.navigator.standalone)
// Fix min height for isMobileDevice when run in full screen mode from home screen
// so the footer appears in the right place
$('body div#torrent_container').css('min-height', '338px');
$("label[for=torrent_upload_url]").text("URL: ");
} else {
// Fix for non-Safari-3 browsers: dark borders to replace shadows.
$('div.dialog_container div.dialog_window').css('border', '1px solid #777');
}
if ($.browser.safari) {
// Move search field's margin down for the styled input
$('#torrent_search').css('margin-top', 3);
};
// Initialise the dialog controller
dialog = new Dialog();
if (isMobileDevice) {
window.onload = function () {
setTimeout(function () {
window.scrollTo(0, 1);
}, 500);
};
window.onorientationchange = function () {
setTimeout(function () {
window.scrollTo(0, 1);
}, 100);
};
if (window.navigator.standalone) {
// Fix min height for isMobileDevice when run in full screen mode from home screen
// so the footer appears in the right place
$('body div#torrent_container').css('min-height', '338px');
};
$("label[for=torrent_upload_url]").text("URL: ");
} else {
// Fix for non-Safari-3 browsers: dark borders to replace shadows.
$('div.dialog_container div.dialog_window').css('border', '1px solid #777');
};
// Initialise the main Transmission controller
transmission = new Transmission();
// Initialise the dialog controller
dialog = new Dialog();
// Initialise the main Transmission controller
transmission = new Transmission();
});
/**
* Checks to see if the content actually changed before poking the DOM.
*/
function setInnerHTML(e, html)
{
if (!e)
return;
function setInnerHTML(e, html) {
if (!e) {
return;
};
/* innerHTML is listed as a string, but the browser seems to change it.
* For example, "&infin;" gets changed to "∞" somewhere down the line.
* So, let's use an arbitrary different field to test our state... */
if (e.currentHTML != html)
{
e.currentHTML = html;
e.innerHTML = html;
}
/* innerHTML is listed as a string, but the browser seems to change it.
* For example, "&infin;" gets changed to "∞" somewhere down the line.
* So, let's use an arbitrary different field to test our state... */
if (e.currentHTML != html) {
e.currentHTML = html;
e.innerHTML = html;
};
};
function sanitizeText(text)
{
return text.replace(/</g, "&lt;").replace(/>/g, "&gt;");
function sanitizeText(text) {
return text.replace(/</g, "&lt;").replace(/>/g, "&gt;");
};
/**
@ -102,99 +121,100 @@ function sanitizeText(text)
* on torrents whose state hasn't changed since the last update,
* so see if the text actually changed before poking the DOM.
*/
function setTextContent(e, text)
{
if (e && (e.textContent != text))
e.textContent = text;
function setTextContent(e, text) {
if (e && (e.textContent != text)) {
e.textContent = text;
};
};
/*
* Given a numerator and denominator, return a ratio string
*/
Math.ratio = function(numerator, denominator) {
var result = Math.floor(100 * numerator / denominator) / 100;
Math.ratio = function (numerator, denominator) {
var result = Math.floor(100 * numerator / denominator) / 100;
// check for special cases
if (result==Number.POSITIVE_INFINITY || result==Number.NEGATIVE_INFINITY) result = -2;
else if (isNaN(result)) result = -1;
// check for special cases
if (result == Number.POSITIVE_INFINITY || result == Number.NEGATIVE_INFINITY) {
result = -2;
} else if (isNaN(result)) {
result = -1;
};
return result;
return result;
};
/**
* Round a string of a number to a specified number of decimal places
*/
Number.prototype.toTruncFixed = function(place) {
var ret = Math.floor(this * Math.pow (10, place)) / Math.pow(10, place);
return ret.toFixed(place);
}
Number.prototype.toTruncFixed = function (place) {
var ret = Math.floor(this * Math.pow(10, place)) / Math.pow(10, place);
return ret.toFixed(place);
};
Number.prototype.toStringWithCommas = function() {
Number.prototype.toStringWithCommas = function () {
return this.toString().replace(/\B(?=(?:\d{3})+(?!\d))/g, ",");
}
};
/*
* Trim whitespace from a string
*/
String.prototype.trim = function () {
return this.replace(/^\s*/, "").replace(/\s*$/, "");
}
return this.replace(/^\s*/, "").replace(/\s*$/, "");
};
/***
**** Preferences
***/
**** Preferences
***/
function Prefs() { }
Prefs.prototype = { };
function Prefs() {};
Prefs.prototype = {};
Prefs._RefreshRate = 'refresh_rate';
Prefs._RefreshRate = 'refresh_rate';
Prefs._FilterMode = 'filter';
Prefs._FilterAll = 'all';
Prefs._FilterActive = 'active';
Prefs._FilterSeeding = 'seeding';
Prefs._FilterDownloading = 'downloading';
Prefs._FilterPaused = 'paused';
Prefs._FilterFinished = 'finished';
Prefs._FilterMode = 'filter';
Prefs._FilterAll = 'all';
Prefs._FilterActive = 'active';
Prefs._FilterSeeding = 'seeding';
Prefs._FilterDownloading = 'downloading';
Prefs._FilterPaused = 'paused';
Prefs._FilterFinished = 'finished';
Prefs._SortDirection = 'sort_direction';
Prefs._SortAscending = 'ascending';
Prefs._SortDescending = 'descending';
Prefs._SortDirection = 'sort_direction';
Prefs._SortAscending = 'ascending';
Prefs._SortDescending = 'descending';
Prefs._SortMethod = 'sort_method';
Prefs._SortByAge = 'age';
Prefs._SortByActivity = 'activity';
Prefs._SortByName = 'name';
Prefs._SortByQueue = 'queue_order';
Prefs._SortBySize = 'size';
Prefs._SortByProgress = 'percent_completed';
Prefs._SortByRatio = 'ratio';
Prefs._SortByState = 'state';
Prefs._SortMethod = 'sort_method';
Prefs._SortByAge = 'age';
Prefs._SortByActivity = 'activity';
Prefs._SortByName = 'name';
Prefs._SortByQueue = 'queue_order';
Prefs._SortBySize = 'size';
Prefs._SortByProgress = 'percent_completed';
Prefs._SortByRatio = 'ratio';
Prefs._SortByState = 'state';
Prefs._CompactDisplayState= 'compact_display_state';
Prefs._CompactDisplayState = 'compact_display_state';
Prefs._Defaults =
{
'filter': 'all',
'refresh_rate' : 5,
'sort_direction': 'ascending',
'sort_method': 'name',
'turtle-state' : false,
'compact_display_state' : false
Prefs._Defaults = {
'filter': 'all',
'refresh_rate': 5,
'sort_direction': 'ascending',
'sort_method': 'name',
'turtle-state': false,
'compact_display_state': false
};
/*
* Set a preference option
*/
Prefs.setValue = function(key, val)
{
if (!(key in Prefs._Defaults))
console.warn("unrecognized preference key '%s'", key);
Prefs.setValue = function (key, val) {
if (!(key in Prefs._Defaults)) {
console.warn("unrecognized preference key '%s'", key);
};
var date = new Date();
date.setFullYear (date.getFullYear() + 1);
document.cookie = key+"="+val+"; expires="+date.toGMTString()+"; path=/";
var date = new Date();
date.setFullYear(date.getFullYear() + 1);
document.cookie = key + "=" + val + "; expires=" + date.toGMTString() + "; path=/";
};
/**
@ -203,26 +223,31 @@ Prefs.setValue = function(key, val)
* @param key the preference's key
* @param fallback if the option isn't set, return this instead
*/
Prefs.getValue = function(key, fallback)
{
var val;
Prefs.getValue = function (key, fallback) {
var val;
if (!(key in Prefs._Defaults))
console.warn("unrecognized preference key '%s'", key);
if (!(key in Prefs._Defaults)) {
console.warn("unrecognized preference key '%s'", key);
};
var lines = document.cookie.split(';');
for (var i=0, len=lines.length; !val && i<len; ++i) {
var line = lines[i].trim();
var delim = line.indexOf('=');
if ((delim === key.length) && line.indexOf(key) === 0)
val = line.substring(delim + 1);
}
var lines = document.cookie.split(';');
for (var i = 0, len = lines.length; !val && i < len; ++i) {
var line = lines[i].trim();
var delim = line.indexOf('=');
if ((delim === key.length) && line.indexOf(key) === 0) {
val = line.substring(delim + 1);
};
};
// FIXME: we support strings and booleans... add number support too?
if (!val) val = fallback;
else if (val === 'true') val = true;
else if (val === 'false') val = false;
return val;
// FIXME: we support strings and booleans... add number support too?
if (!val) {
val = fallback;
} else if (val === 'true') {
val = true;
} else if (val === 'false') {
val = false;
};
return val;
};
/**
@ -230,41 +255,40 @@ Prefs.getValue = function(key, fallback)
*
* @pararm o object to be populated (optional)
*/
Prefs.getClutchPrefs = function(o)
{
if (!o)
o = { };
for (var key in Prefs._Defaults)
o[key] = Prefs.getValue(key, Prefs._Defaults[key]);
return o;
Prefs.getClutchPrefs = function (o) {
if (!o) {
o = {};
};
for (var key in Prefs._Defaults) {
o[key] = Prefs.getValue(key, Prefs._Defaults[key]);
};
return o;
};
// forceNumeric() plug-in implementation
jQuery.fn.forceNumeric = function () {
return this.each(function () {
$(this).keydown(function (e) {
var key = e.which || e.keyCode;
return !e.shiftKey && !e.altKey && !e.ctrlKey &&
// numbers
key >= 48 && key <= 57 ||
// Numeric keypad
key >= 96 && key <= 105 ||
// comma, period and minus, . on keypad
key === 190 || key === 188 || key === 109 || key === 110 ||
// Backspace and Tab and Enter
key === 8 || key === 9 || key === 13 ||
// Home and End
key === 35 || key === 36 ||
// left and right arrows
key === 37 || key === 39 ||
// Del and Ins
key === 46 || key === 45;
});
});
return this.each(function () {
$(this).keydown(function (e) {
var key = e.which || e.keyCode;
return !e.shiftKey && !e.altKey && !e.ctrlKey &&
// numbers
key >= 48 && key <= 57 ||
// Numeric keypad
key >= 96 && key <= 105 ||
// comma, period and minus, . on keypad
key === 190 || key === 188 || key === 109 || key === 110 ||
// Backspace and Tab and Enter
key === 8 || key === 9 || key === 13 ||
// Home and End
key === 35 || key === 36 ||
// left and right arrows
key === 37 || key === 39 ||
// Del and Ins
key === 46 || key === 45;
});
});
}
/**
* http://blog.stevenlevithan.com/archives/parseuri
*
@ -272,31 +296,35 @@ jQuery.fn.forceNumeric = function () {
* (c) Steven Levithan <stevenlevithan.com>
* MIT License
*/
function parseUri (str) {
var o = parseUri.options,
m = o.parser[o.strictMode ? "strict" : "loose"].exec(str),
uri = {},
i = 14;
function parseUri(str) {
var o = parseUri.options;
var m = o.parser[o.strictMode ? "strict" : "loose"].exec(str);
var uri = {};
var i = 14;
while (i--) uri[o.key[i]] = m[i] || "";
while (i--) {
uri[o.key[i]] = m[i] || "";
};
uri[o.q.name] = {};
uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
if ($1) uri[o.q.name][$1] = $2;
});
uri[o.q.name] = {};
uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
if ($1) {
uri[o.q.name][$1] = $2;
};
});
return uri;
return uri;
};
parseUri.options = {
strictMode: false,
key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],
q: {
name: "queryKey",
parser: /(?:^|&)([^&=]*)=?([^&]*)/g
},
parser: {
strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
}
strictMode: false,
key: ["source", "protocol", "authority", "userInfo", "user", "password", "host", "port", "relative", "path", "directory", "file", "query", "anchor"],
q: {
name: "queryKey",
parser: /(?:^|&)([^&=]*)=?([^&]*)/g
},
parser: {
strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
}
};

View File

@ -5,109 +5,107 @@
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*/
function Dialog(){
this.initialize();
}
function Dialog() {
this.initialize();
};
Dialog.prototype = {
/*
* Constructor
*/
initialize: function() {
/*
* Constructor
*/
initialize: function () {
/*
* Private Interface Variables
*/
this._container = $('#dialog_container');
this._heading = $('#dialog_heading');
this._message = $('#dialog_message');
this._cancel_button = $('#dialog_cancel_button');
this._confirm_button = $('#dialog_confirm_button');
this._callback = null;
/*
* Private Interface Variables
*/
this._container = $('#dialog_container');
this._heading = $('#dialog_heading');
this._message = $('#dialog_message');
this._cancel_button = $('#dialog_cancel_button');
this._confirm_button = $('#dialog_confirm_button');
this._callback = null;
// Observe the buttons
this._cancel_button.bind('click', {dialog: this}, this.onCancelClicked);
this._confirm_button.bind('click', {dialog: this}, this.onConfirmClicked);
},
// Observe the buttons
this._cancel_button.bind('click', {
dialog: this
}, this.onCancelClicked);
this._confirm_button.bind('click', {
dialog: this
}, this.onConfirmClicked);
},
/*--------------------------------------------
*
* E V E N T F U N C T I O N S
*
*--------------------------------------------*/
hideDialog: function () {
$('body.dialog_showing').removeClass('dialog_showing');
this._container.hide();
transmission.hideMobileAddressbar();
transmission.updateButtonStates();
},
onCancelClicked: function (event) {
event.data.dialog.hideDialog();
},
onConfirmClicked: function (event) {
var dialog = event.data.dialog;
dialog._callback();
dialog.hideDialog();
},
/*--------------------------------------------
*
* E V E N T F U N C T I O N S
*
*--------------------------------------------*/
/*--------------------------------------------
*
* I N T E R F A C E F U N C T I O N S
*
*--------------------------------------------*/
hideDialog: function()
{
$('body.dialog_showing').removeClass('dialog_showing');
this._container.hide();
transmission.hideMobileAddressbar();
transmission.updateButtonStates();
},
/*
* Display a confirm dialog
*/
confirm: function (dialog_heading, dialog_message, confirm_button_label,
callback, cancel_button_label) {
if (!isMobileDevice) {
$('.dialog_container').hide();
};
setTextContent(this._heading[0], dialog_heading);
setTextContent(this._message[0], dialog_message);
setTextContent(this._cancel_button[0], cancel_button_label || 'Cancel');
setTextContent(this._confirm_button[0], confirm_button_label);
this._confirm_button.show();
this._callback = callback;
$('body').addClass('dialog_showing');
this._container.show();
transmission.updateButtonStates();
if (isMobileDevice) {
transmission.hideMobileAddressbar();
};
},
onCancelClicked: function(event)
{
event.data.dialog.hideDialog();
},
onConfirmClicked: function(event)
{
var dialog = event.data.dialog;
dialog._callback();
dialog.hideDialog();
},
/*--------------------------------------------
*
* I N T E R F A C E F U N C T I O N S
*
*--------------------------------------------*/
/*
* Display a confirm dialog
*/
confirm: function(dialog_heading, dialog_message, confirm_button_label,
callback, cancel_button_label)
{
if (!isMobileDevice)
$('.dialog_container').hide();
setTextContent(this._heading[0], dialog_heading);
setTextContent(this._message[0], dialog_message);
setTextContent(this._cancel_button[0], cancel_button_label || 'Cancel');
setTextContent(this._confirm_button[0], confirm_button_label);
this._confirm_button.show();
this._callback = callback;
$('body').addClass('dialog_showing');
this._container.show();
transmission.updateButtonStates();
if (isMobileDevice)
transmission.hideMobileAddressbar();
},
/*
* Display an alert dialog
*/
alert: function(dialog_heading, dialog_message, cancel_button_label) {
if (!isMobileDevice)
$('.dialog_container').hide();
setTextContent(this._heading[0], dialog_heading);
setTextContent(this._message[0], dialog_message);
// jquery::hide() doesn't work here in Safari for some odd reason
this._confirm_button.css('display', 'none');
setTextContent(this._cancel_button[0], cancel_button_label);
// Just in case
$('#upload_container').hide();
$('#move_container').hide();
$('body').addClass('dialog_showing');
transmission.updateButtonStates();
if (isMobileDevice)
transmission.hideMobileAddressbar();
this._container.show();
}
}
/*
* Display an alert dialog
*/
alert: function (dialog_heading, dialog_message, cancel_button_label) {
if (!isMobileDevice) {
$('.dialog_container').hide();
};
setTextContent(this._heading[0], dialog_heading);
setTextContent(this._message[0], dialog_message);
// jquery::hide() doesn't work here in Safari for some odd reason
this._confirm_button.css('display', 'none');
setTextContent(this._cancel_button[0], cancel_button_label);
// Just in case
$('#upload_container').hide();
$('#move_container').hide();
$('body').addClass('dialog_showing');
transmission.updateButtonStates();
if (isMobileDevice) {
transmission.hideMobileAddressbar();
};
this._container.show();
}
};

View File

@ -5,190 +5,205 @@
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*/
function FileRow(torrent, depth, name, indices, even)
{
var fields = {
have: 0,
indices: [],
isWanted: true,
priorityLow: false,
priorityNormal: false,
priorityHigh: false,
me: this,
size: 0,
torrent: null
},
function FileRow(torrent, depth, name, indices, even) {
var fields = {
have: 0,
indices: [],
isWanted: true,
priorityLow: false,
priorityNormal: false,
priorityHigh: false,
me: this,
size: 0,
torrent: null
};
elements = {
priority_low_button: null,
priority_normal_button: null,
priority_high_button: null,
progress: null,
root: null
},
var elements = {
priority_low_button: null,
priority_normal_button: null,
priority_high_button: null,
progress: null,
root: null
};
initialize = function(torrent, depth, name, indices, even) {
fields.torrent = torrent;
fields.indices = indices;
createRow(torrent, depth, name, even);
},
var initialize = function (torrent, depth, name, indices, even) {
fields.torrent = torrent;
fields.indices = indices;
createRow(torrent, depth, name, even);
};
refreshWantedHTML = function()
{
var e = $(elements.root);
e.toggleClass('skip', !fields.isWanted);
e.toggleClass('complete', isDone());
$(e[0].checkbox).prop('disabled', !isEditable());
$(e[0].checkbox).prop('checked', fields.isWanted);
},
refreshProgressHTML = function()
{
var pct = 100 * (fields.size ? (fields.have / fields.size) : 1.0),
c = [ Transmission.fmt.size(fields.have),
' of ',
Transmission.fmt.size(fields.size),
' (',
Transmission.fmt.percentString(pct),
'%)' ].join('');
setTextContent(elements.progress, c);
},
refreshImpl = function() {
var i,
file,
have = 0,
size = 0,
wanted = false,
low = false,
normal = false,
high = false;
var refreshWantedHTML = function () {
var e = $(elements.root);
e.toggleClass('skip', !fields.isWanted);
e.toggleClass('complete', isDone());
$(e[0].checkbox).prop('disabled', !isEditable());
$(e[0].checkbox).prop('checked', fields.isWanted);
};
// loop through the file_indices that affect this row
for (i=0; i<fields.indices.length; ++i) {
file = fields.torrent.getFile (fields.indices[i]);
have += file.bytesCompleted;
size += file.length;
wanted |= file.wanted;
switch (file.priority) {
case -1: low = true; break;
case 0: normal = true; break;
case 1: high = true; break;
}
}
var refreshProgressHTML = function () {
var pct = 100 * (fields.size ? (fields.have / fields.size) : 1.0)
var c = [Transmission.fmt.size(fields.have), ' of ', Transmission.fmt.size(fields.size), ' (', Transmission.fmt.percentString(pct), '%)'].join('');
setTextContent(elements.progress, c);
};
if ((fields.have != have) || (fields.size != size)) {
fields.have = have;
fields.size = size;
refreshProgressHTML();
}
var refreshImpl = function () {
var i,
file,
have = 0,
size = 0,
wanted = false,
low = false,
normal = false,
high = false;
if (fields.isWanted !== wanted) {
fields.isWanted = wanted;
refreshWantedHTML();
}
// loop through the file_indices that affect this row
for (i = 0; i < fields.indices.length; ++i) {
file = fields.torrent.getFile(fields.indices[i]);
have += file.bytesCompleted;
size += file.length;
wanted |= file.wanted;
switch (file.priority) {
case -1:
low = true;
break;
case 0:
normal = true;
break;
case 1:
high = true;
break;
}
}
if (fields.priorityLow !== low) {
fields.priorityLow = low;
$(elements.priority_low_button).toggleClass('selected', low);
}
if ((fields.have != have) || (fields.size != size)) {
fields.have = have;
fields.size = size;
refreshProgressHTML();
}
if (fields.priorityNormal !== normal) {
fields.priorityNormal = normal;
$(elements.priority_normal_button).toggleClass('selected', normal);
}
if (fields.isWanted !== wanted) {
fields.isWanted = wanted;
refreshWantedHTML();
}
if (fields.priorityHigh !== high) {
fields.priorityHigh = high;
$(elements.priority_high_button).toggleClass('selected', high);
}
},
if (fields.priorityLow !== low) {
fields.priorityLow = low;
$(elements.priority_low_button).toggleClass('selected', low);
}
isDone = function () {
return fields.have >= fields.size;
},
isEditable = function () {
return (fields.torrent.getFileCount()>1) && !isDone();
},
if (fields.priorityNormal !== normal) {
fields.priorityNormal = normal;
$(elements.priority_normal_button).toggleClass('selected', normal);
}
createRow = function(torrent, depth, name, even) {
var e, root, box;
if (fields.priorityHigh !== high) {
fields.priorityHigh = high;
$(elements.priority_high_button).toggleClass('selected', high);
}
};
root = document.createElement('li');
root.className = 'inspector_torrent_file_list_entry' + (even?'even':'odd');
elements.root = root;
var isDone = function () {
return fields.have >= fields.size;
};
e = document.createElement('input');
e.type = 'checkbox';
e.className = "file_wanted_control";
e.title = 'Download file';
$(e).change(function(ev){ fireWantedChanged( $(ev.currentTarget).prop('checked')); });
root.checkbox = e;
root.appendChild(e);
var isEditable = function () {
return (fields.torrent.getFileCount() > 1) && !isDone();
};
e = document.createElement('div');
e.className = 'file-priority-radiobox';
box = e;
var createRow = function (torrent, depth, name, even) {
var e, root, box;
e = document.createElement('div');
e.className = 'low';
e.title = 'Low Priority';
$(e).click(function(){ firePriorityChanged(-1); });
elements.priority_low_button = e;
box.appendChild(e);
root = document.createElement('li');
root.className = 'inspector_torrent_file_list_entry' + (even ? 'even' : 'odd');
elements.root = root;
e = document.createElement('div');
e.className = 'normal';
e.title = 'Normal Priority';
$(e).click(function(){ firePriorityChanged(0); });
elements.priority_normal_button = e;
box.appendChild(e);
e = document.createElement('input');
e.type = 'checkbox';
e.className = "file_wanted_control";
e.title = 'Download file';
$(e).change(function (ev) {
fireWantedChanged($(ev.currentTarget).prop('checked'));
});
root.checkbox = e;
root.appendChild(e);
e = document.createElement('div');
e.title = 'High Priority';
e.className = 'high';
$(e).click(function(){ firePriorityChanged(1); });
elements.priority_high_button = e;
box.appendChild(e);
e = document.createElement('div');
e.className = 'file-priority-radiobox';
box = e;
root.appendChild(box);
e = document.createElement('div');
e.className = 'low';
e.title = 'Low Priority';
$(e).click(function () {
firePriorityChanged(-1);
});
elements.priority_low_button = e;
box.appendChild(e);
e = document.createElement('div');
e.className = "inspector_torrent_file_list_entry_name";
setTextContent(e, name);
$(e).click(function(){ fireNameClicked(-1); });
root.appendChild(e);
e = document.createElement('div');
e.className = 'normal';
e.title = 'Normal Priority';
$(e).click(function () {
firePriorityChanged(0);
});
elements.priority_normal_button = e;
box.appendChild(e);
e = document.createElement('div');
e.className = "inspector_torrent_file_list_entry_progress";
root.appendChild(e);
$(e).click(function(){ fireNameClicked(-1); });
elements.progress = e;
e = document.createElement('div');
e.title = 'High Priority';
e.className = 'high';
$(e).click(function () {
firePriorityChanged(1);
});
elements.priority_high_button = e;
box.appendChild(e);
$(root).css('margin-left', '' + (depth*16) + 'px');
root.appendChild(box);
refreshImpl();
return root;
},
e = document.createElement('div');
e.className = "inspector_torrent_file_list_entry_name";
setTextContent(e, name);
$(e).click(function () {
fireNameClicked(-1);
});
root.appendChild(e);
fireWantedChanged = function(do_want) {
$(fields.me).trigger('wantedToggled',[ fields.indices, do_want ]);
},
firePriorityChanged = function(priority) {
$(fields.me).trigger('priorityToggled',[ fields.indices, priority ]);
},
fireNameClicked = function() {
$(fields.me).trigger('nameClicked',[ fields.me, fields.indices ]);
};
e = document.createElement('div');
e.className = "inspector_torrent_file_list_entry_progress";
root.appendChild(e);
$(e).click(function () {
fireNameClicked(-1);
});
elements.progress = e;
/***
**** PUBLIC
***/
$(root).css('margin-left', '' + (depth * 16) + 'px');
this.getElement = function() {
return elements.root;
};
this.refresh = function() {
refreshImpl();
};
refreshImpl();
return root;
};
initialize(torrent, depth, name, indices, even);
var fireWantedChanged = function (do_want) {
$(fields.me).trigger('wantedToggled', [fields.indices, do_want]);
};
var firePriorityChanged = function (priority) {
$(fields.me).trigger('priorityToggled', [fields.indices, priority]);
};
var fireNameClicked = function () {
$(fields.me).trigger('nameClicked', [fields.me, fields.indices]);
};
/***
**** PUBLIC
***/
this.getElement = function () {
return elements.root;
};
this.refresh = function () {
refreshImpl();
};
initialize(torrent, depth, name, indices, even);
};

View File

@ -5,309 +5,290 @@
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*/
Transmission.fmt = (function()
{
var speed_K = 1000;
var speed_B_str = 'B/s';
var speed_K_str = 'kB/s';
var speed_M_str = 'MB/s';
var speed_G_str = 'GB/s';
var speed_T_str = 'TB/s';
Transmission.fmt = (function () {
var speed_K = 1000;
var speed_B_str = 'B/s';
var speed_K_str = 'kB/s';
var speed_M_str = 'MB/s';
var speed_G_str = 'GB/s';
var speed_T_str = 'TB/s';
var size_K = 1000;
var size_B_str = 'B';
var size_K_str = 'kB';
var size_M_str = 'MB';
var size_G_str = 'GB';
var size_T_str = 'TB';
var size_K = 1000;
var size_B_str = 'B';
var size_K_str = 'kB';
var size_M_str = 'MB';
var size_G_str = 'GB';
var size_T_str = 'TB';
var mem_K = 1024;
var mem_B_str = 'B';
var mem_K_str = 'KiB';
var mem_M_str = 'MiB';
var mem_G_str = 'GiB';
var mem_T_str = 'TiB';
var mem_K = 1024;
var mem_B_str = 'B';
var mem_K_str = 'KiB';
var mem_M_str = 'MiB';
var mem_G_str = 'GiB';
var mem_T_str = 'TiB';
return {
return {
updateUnits: function(u)
{
/*
speed_K = u['speed-bytes'];
speed_K_str = u['speed-units'][0];
speed_M_str = u['speed-units'][1];
speed_G_str = u['speed-units'][2];
speed_T_str = u['speed-units'][3];
/*
* Format a percentage to a string
*/
percentString: function (x) {
if (x < 10.0) {
return x.toTruncFixed(2);
} else if (x < 100.0) {
return x.toTruncFixed(1);
} else {
return x.toTruncFixed(0);
}
},
size_K = u['size-bytes'];
size_K_str = u['size-units'][0];
size_M_str = u['size-units'][1];
size_G_str = u['size-units'][2];
size_T_str = u['size-units'][3];
/*
* Format a ratio to a string
*/
ratioString: function (x) {
if (x === -1) {
return "None";
}
if (x === -2) {
return '&infin;';
}
return this.percentString(x);
},
mem_K = u['memory-bytes'];
mem_K_str = u['memory-units'][0];
mem_M_str = u['memory-units'][1];
mem_G_str = u['memory-units'][2];
mem_T_str = u['memory-units'][3];
*/
},
/**
* Formats the a memory size into a human-readable string
* @param {Number} bytes the filesize in bytes
* @return {String} human-readable string
*/
mem: function (bytes) {
if (bytes < mem_K)
return [bytes, mem_B_str].join(' ');
/*
* Format a percentage to a string
*/
percentString: function(x) {
if (x < 10.0)
return x.toTruncFixed(2);
else if (x < 100.0)
return x.toTruncFixed(1);
else
return x.toTruncFixed(0);
},
var convertedSize;
var unit;
/*
* Format a ratio to a string
*/
ratioString: function(x) {
if (x === -1)
return "None";
if (x === -2)
return '&infin;';
return this.percentString(x);
},
if (bytes < Math.pow(mem_K, 2)) {
convertedSize = bytes / mem_K;
unit = mem_K_str;
} else if (bytes < Math.pow(mem_K, 3)) {
convertedSize = bytes / Math.pow(mem_K, 2);
unit = mem_M_str;
} else if (bytes < Math.pow(mem_K, 4)) {
convertedSize = bytes / Math.pow(mem_K, 3);
unit = mem_G_str;
} else {
convertedSize = bytes / Math.pow(mem_K, 4);
unit = mem_T_str;
}
/**
* Formats the a memory size into a human-readable string
* @param {Number} bytes the filesize in bytes
* @return {String} human-readable string
*/
mem: function(bytes)
{
if (bytes < mem_K)
return [ bytes, mem_B_str ].join(' ');
// try to have at least 3 digits and at least 1 decimal
return convertedSize <= 9.995 ? [convertedSize.toTruncFixed(2), unit].join(' ') : [convertedSize.toTruncFixed(1), unit].join(' ');
},
var convertedSize;
var unit;
/**
* Formats the a disk capacity or file size into a human-readable string
* @param {Number} bytes the filesize in bytes
* @return {String} human-readable string
*/
size: function (bytes) {
if (bytes < size_K) {
return [bytes, size_B_str].join(' ');
}
if (bytes < Math.pow(mem_K, 2))
{
convertedSize = bytes / mem_K;
unit = mem_K_str;
}
else if (bytes < Math.pow(mem_K, 3))
{
convertedSize = bytes / Math.pow(mem_K, 2);
unit = mem_M_str;
}
else if (bytes < Math.pow(mem_K, 4))
{
convertedSize = bytes / Math.pow(mem_K, 3);
unit = mem_G_str;
}
else
{
convertedSize = bytes / Math.pow(mem_K, 4);
unit = mem_T_str;
}
var convertedSize;
var unit;
// try to have at least 3 digits and at least 1 decimal
return convertedSize <= 9.995 ? [ convertedSize.toTruncFixed(2), unit ].join(' ')
: [ convertedSize.toTruncFixed(1), unit ].join(' ');
},
if (bytes < Math.pow(size_K, 2)) {
convertedSize = bytes / size_K;
unit = size_K_str;
} else if (bytes < Math.pow(size_K, 3)) {
convertedSize = bytes / Math.pow(size_K, 2);
unit = size_M_str;
} else if (bytes < Math.pow(size_K, 4)) {
convertedSize = bytes / Math.pow(size_K, 3);
unit = size_G_str;
} else {
convertedSize = bytes / Math.pow(size_K, 4);
unit = size_T_str;
}
/**
* Formats the a disk capacity or file size into a human-readable string
* @param {Number} bytes the filesize in bytes
* @return {String} human-readable string
*/
size: function(bytes)
{
if (bytes < size_K)
return [ bytes, size_B_str ].join(' ');
// try to have at least 3 digits and at least 1 decimal
return convertedSize <= 9.995 ? [convertedSize.toTruncFixed(2), unit].join(' ') : [convertedSize.toTruncFixed(1), unit].join(' ');
},
var convertedSize;
var unit;
speedBps: function (Bps) {
return this.speed(this.toKBps(Bps));
},
if (bytes < Math.pow(size_K, 2))
{
convertedSize = bytes / size_K;
unit = size_K_str;
}
else if (bytes < Math.pow(size_K, 3))
{
convertedSize = bytes / Math.pow(size_K, 2);
unit = size_M_str;
}
else if (bytes < Math.pow(size_K, 4))
{
convertedSize = bytes / Math.pow(size_K, 3);
unit = size_G_str;
}
else
{
convertedSize = bytes / Math.pow(size_K, 4);
unit = size_T_str;
}
toKBps: function (Bps) {
return Math.floor(Bps / speed_K);
},
// try to have at least 3 digits and at least 1 decimal
return convertedSize <= 9.995 ? [ convertedSize.toTruncFixed(2), unit ].join(' ')
: [ convertedSize.toTruncFixed(1), unit ].join(' ');
},
speed: function (KBps) {
var speed = KBps;
speedBps: function(Bps)
{
return this.speed(this.toKBps(Bps));
},
if (speed <= 999.95) { // 0 KBps to 999 K
return [speed.toTruncFixed(0), speed_K_str].join(' ');
}
toKBps: function(Bps)
{
return Math.floor(Bps / speed_K);
},
speed /= speed_K;
speed: function(KBps)
{
var speed = KBps;
if (speed <= 99.995) { // 1 M to 99.99 M
return [speed.toTruncFixed(2), speed_M_str].join(' ');
}
if (speed <= 999.95) { // 100 M to 999.9 M
return [speed.toTruncFixed(1), speed_M_str].join(' ');
}
if (speed <= 999.95) // 0 KBps to 999 K
return [ speed.toTruncFixed(0), speed_K_str ].join(' ');
// insane speeds
speed /= speed_K;
return [speed.toTruncFixed(2), speed_G_str].join(' ');
},
speed /= speed_K;
timeInterval: function (seconds) {
var days = Math.floor(seconds / 86400),
hours = Math.floor((seconds % 86400) / 3600),
minutes = Math.floor((seconds % 3600) / 60),
seconds = Math.floor(seconds % 60),
d = days + ' ' + (days > 1 ? 'days' : 'day'),
h = hours + ' ' + (hours > 1 ? 'hours' : 'hour'),
m = minutes + ' ' + (minutes > 1 ? 'minutes' : 'minute'),
s = seconds + ' ' + (seconds > 1 ? 'seconds' : 'second');
if (speed <= 99.995) // 1 M to 99.99 M
return [ speed.toTruncFixed(2), speed_M_str ].join(' ');
if (speed <= 999.95) // 100 M to 999.9 M
return [ speed.toTruncFixed(1), speed_M_str ].join(' ');
if (days) {
if (days >= 4 || !hours) {
return d;
}
return d + ', ' + h;
}
if (hours) {
if (hours >= 4 || !minutes) {
return h;
}
return h + ', ' + m;
}
if (minutes) {
if (minutes >= 4 || !seconds) {
return m;
}
return m + ', ' + s;
}
return s;
},
// insane speeds
speed /= speed_K;
return [ speed.toTruncFixed(2), speed_G_str ].join(' ');
},
timestamp: function (seconds) {
if (!seconds) {
return 'N/A';
}
timeInterval: function(seconds)
{
var days = Math.floor (seconds / 86400),
hours = Math.floor ((seconds % 86400) / 3600),
minutes = Math.floor ((seconds % 3600) / 60),
seconds = Math.floor (seconds % 60),
d = days + ' ' + (days > 1 ? 'days' : 'day'),
h = hours + ' ' + (hours > 1 ? 'hours' : 'hour'),
m = minutes + ' ' + (minutes > 1 ? 'minutes' : 'minute'),
s = seconds + ' ' + (seconds > 1 ? 'seconds' : 'second');
var myDate = new Date(seconds * 1000);
var now = new Date();
if (days) {
if (days >= 4 || !hours)
return d;
return d + ', ' + h;
}
if (hours) {
if (hours >= 4 || !minutes)
return h;
return h + ', ' + m;
}
if (minutes) {
if (minutes >= 4 || !seconds)
return m;
return m + ', ' + s;
}
return s;
},
var date = "";
var time = "";
timestamp: function(seconds)
{
if (!seconds)
return 'N/A';
var sameYear = now.getFullYear() === myDate.getFullYear();
var sameMonth = now.getMonth() === myDate.getMonth();
var myDate = new Date(seconds*1000);
var now = new Date();
var dateDiff = now.getDate() - myDate.getDate();
if (sameYear && sameMonth && Math.abs(dateDiff) <= 1) {
if (dateDiff === 0) {
date = "Today";
} else if (dateDiff === 1) {
date = "Yesterday";
} else {
date = "Tomorrow";
}
} else {
date = myDate.toDateString();
}
var date = "";
var time = "";
var hours = myDate.getHours();
var period = "AM";
if (hours > 12) {
hours = hours - 12;
period = "PM";
}
if (hours === 0) {
hours = 12;
}
if (hours < 10) {
hours = "0" + hours;
}
var minutes = myDate.getMinutes();
if (minutes < 10) {
minutes = "0" + minutes;
}
var seconds = myDate.getSeconds();
if (seconds < 10) {
seconds = "0" + seconds;
}
var sameYear = now.getFullYear() === myDate.getFullYear();
var sameMonth = now.getMonth() === myDate.getMonth();
time = [hours, minutes, seconds].join(':');
var dateDiff = now.getDate() - myDate.getDate();
if (sameYear && sameMonth && Math.abs(dateDiff) <= 1){
if (dateDiff === 0){
date = "Today";
}
else if (dateDiff === 1){
date = "Yesterday";
}
else{
date = "Tomorrow";
}
}
else{
date = myDate.toDateString();
}
return [date, time, period].join(' ');
},
var hours = myDate.getHours();
var period = "AM";
if (hours > 12){
hours = hours - 12;
period = "PM";
}
if (hours === 0){
hours = 12;
}
if (hours < 10){
hours = "0" + hours;
}
var minutes = myDate.getMinutes();
if (minutes < 10){
minutes = "0" + minutes;
}
var seconds = myDate.getSeconds();
if (seconds < 10){
seconds = "0" + seconds;
}
ngettext: function (msgid, msgid_plural, n) {
// TODO(i18n): http://doc.qt.digia.com/4.6/i18n-plural-rules.html
return n === 1 ? msgid : msgid_plural;
},
time = [hours, minutes, seconds].join(':');
countString: function (msgid, msgid_plural, n) {
return [n.toStringWithCommas(), this.ngettext(msgid, msgid_plural, n)].join(' ');
},
return [date, time, period].join(' ');
},
peerStatus: function (flagStr) {
var formattedFlags = [];
for (var i = 0, flag; flag = flagStr[i]; ++i) {
var explanation = null;
switch (flag) {
case "O":
explanation = "Optimistic unchoke";
break;
case "D":
explanation = "Downloading from this peer";
break;
case "d":
explanation = "We would download from this peer if they'd let us";
break;
case "U":
explanation = "Uploading to peer";
break;
case "u":
explanation = "We would upload to this peer if they'd ask";
break;
case "K":
explanation = "Peer has unchoked us, but we're not interested";
break;
case "?":
explanation = "We unchoked this peer, but they're not interested";
break;
case "E":
explanation = "Encrypted Connection";
break;
case "H":
explanation = "Peer was discovered through Distributed Hash Table (DHT)";
break;
case "X":
explanation = "Peer was discovered through Peer Exchange (PEX)";
break;
case "I":
explanation = "Peer is an incoming connection";
break;
case "T":
explanation = "Peer is connected via uTP";
break;
};
ngettext: function(msgid, msgid_plural, n)
{
// TODO(i18n): http://doc.qt.digia.com/4.6/i18n-plural-rules.html
return n === 1 ? msgid : msgid_plural;
},
if (!explanation) {
formattedFlags.push(flag);
} else {
formattedFlags.push("<span title=\"" + flag + ': ' + explanation + "\">" + flag + "</span>");
};
};
countString: function(msgid, msgid_plural, n)
{
return [ n.toStringWithCommas(), this.ngettext(msgid,msgid_plural,n) ].join(' ');
},
peerStatus: function( flagStr )
{
var formattedFlags = [];
for (var i=0, flag; flag=flagStr[i]; ++i)
{
var explanation = null;
switch (flag)
{
case "O": explanation = "Optimistic unchoke"; break;
case "D": explanation = "Downloading from this peer"; break;
case "d": explanation = "We would download from this peer if they'd let us"; break;
case "U": explanation = "Uploading to peer"; break;
case "u": explanation = "We would upload to this peer if they'd ask"; break;
case "K": explanation = "Peer has unchoked us, but we're not interested"; break;
case "?": explanation = "We unchoked this peer, but they're not interested"; break;
case "E": explanation = "Encrypted Connection"; break;
case "H": explanation = "Peer was discovered through Distributed Hash Table (DHT)"; break;
case "X": explanation = "Peer was discovered through Peer Exchange (PEX)"; break;
case "I": explanation = "Peer is an incoming connection"; break;
case "T": explanation = "Peer is connected via uTP"; break;
}
if (!explanation) {
formattedFlags.push(flag);
} else {
formattedFlags.push("<span title=\"" + flag + ': ' + explanation + "\">" + flag + "</span>");
}
}
return formattedFlags.join('');
}
}
return formattedFlags.join('');
}
}
})();

File diff suppressed because it is too large Load Diff

View File

@ -1,42 +1,42 @@
var Notifications = {};
$(document).ready(function () {
if (!window.webkitNotifications) {
return;
}
if (!window.webkitNotifications) {
return;
};
var notificationsEnabled = (window.webkitNotifications.checkPermission() === 0),
toggle = $('#toggle_notifications');
var notificationsEnabled = (window.webkitNotifications.checkPermission() === 0)
var toggle = $('#toggle_notifications');
toggle.show();
updateMenuTitle();
$(transmission).bind('downloadComplete seedingComplete', function (event, torrent) {
if (notificationsEnabled) {
var title = (event.type == 'downloadComplete' ? 'Download' : 'Seeding') + ' complete',
content = torrent.getName(),
notification;
toggle.show();
updateMenuTitle();
$(transmission).bind('downloadComplete seedingComplete', function (event, torrent) {
if (notificationsEnabled) {
var title = (event.type == 'downloadComplete' ? 'Download' : 'Seeding') + ' complete',
content = torrent.getName(),
notification;
notification = window.webkitNotifications.createNotification('style/transmission/images/logo.png', title, content);
notification.show();
setTimeout(function () {
notification.cancel();
}, 5000);
};
});
notification = window.webkitNotifications.createNotification('style/transmission/images/logo.png', title, content);
notification.show();
setTimeout(function () {
notification.cancel();
}, 5000);
};
});
function updateMenuTitle() {
toggle.html((notificationsEnabled ? 'Disable' : 'Enable') + ' Notifications');
}
function updateMenuTitle() {
toggle.html((notificationsEnabled ? 'Disable' : 'Enable') + ' Notifications');
};
Notifications.toggle = function () {
if (window.webkitNotifications.checkPermission() !== 0) {
window.webkitNotifications.requestPermission(function () {
notificationsEnabled = (window.webkitNotifications.checkPermission() === 0);
updateMenuTitle();
});
} else {
notificationsEnabled = !notificationsEnabled;
updateMenuTitle();
}
};
Notifications.toggle = function () {
if (window.webkitNotifications.checkPermission() !== 0) {
window.webkitNotifications.requestPermission(function () {
notificationsEnabled = (window.webkitNotifications.checkPermission() === 0);
updateMenuTitle();
});
} else {
notificationsEnabled = !notificationsEnabled;
updateMenuTitle();
};
};
});

View File

@ -7,312 +7,296 @@
function PrefsDialog(remote) {
var data = {
dialog: null,
remote: null,
elements: { },
var data = {
dialog: null,
remote: null,
elements: {},
// all the RPC session keys that we have gui controls for
keys: [
'alt-speed-down',
'alt-speed-time-begin',
'alt-speed-time-day',
'alt-speed-time-enabled',
'alt-speed-time-end',
'alt-speed-up',
'blocklist-enabled',
'blocklist-size',
'blocklist-url',
'dht-enabled',
'download-dir',
'encryption',
'idle-seeding-limit',
'idle-seeding-limit-enabled',
'lpd-enabled',
'peer-limit-global',
'peer-limit-per-torrent',
'peer-port',
'peer-port-random-on-start',
'pex-enabled',
'port-forwarding-enabled',
'rename-partial-files',
'seedRatioLimit',
'seedRatioLimited',
'speed-limit-down',
'speed-limit-down-enabled',
'speed-limit-up',
'speed-limit-up-enabled',
'start-added-torrents',
'utp-enabled'
],
// all the RPC session keys that we have gui controls for
keys: [
'alt-speed-down',
'alt-speed-time-begin',
'alt-speed-time-day',
'alt-speed-time-enabled',
'alt-speed-time-end',
'alt-speed-up',
'blocklist-enabled',
'blocklist-size',
'blocklist-url',
'dht-enabled',
'download-dir',
'encryption',
'idle-seeding-limit',
'idle-seeding-limit-enabled',
'lpd-enabled',
'peer-limit-global',
'peer-limit-per-torrent',
'peer-port',
'peer-port-random-on-start',
'pex-enabled',
'port-forwarding-enabled',
'rename-partial-files',
'seedRatioLimit',
'seedRatioLimited',
'speed-limit-down',
'speed-limit-down-enabled',
'speed-limit-up',
'speed-limit-up-enabled',
'start-added-torrents',
'utp-enabled'
],
// map of keys that are enabled only if a 'parent' key is enabled
groups: {
'alt-speed-time-enabled': ['alt-speed-time-begin',
'alt-speed-time-day',
'alt-speed-time-end' ],
'blocklist-enabled': ['blocklist-url',
'blocklist-update-button' ],
'idle-seeding-limit-enabled': [ 'idle-seeding-limit' ],
'seedRatioLimited': [ 'seedRatioLimit' ],
'speed-limit-down-enabled': [ 'speed-limit-down' ],
'speed-limit-up-enabled': [ 'speed-limit-up' ]
}
},
// map of keys that are enabled only if a 'parent' key is enabled
groups: {
'alt-speed-time-enabled': ['alt-speed-time-begin',
'alt-speed-time-day',
'alt-speed-time-end'
],
'blocklist-enabled': ['blocklist-url',
'blocklist-update-button'
],
'idle-seeding-limit-enabled': ['idle-seeding-limit'],
'seedRatioLimited': ['seedRatioLimit'],
'speed-limit-down-enabled': ['speed-limit-down'],
'speed-limit-up-enabled': ['speed-limit-up']
}
};
initTimeDropDown = function(e)
{
var i, hour, mins, value, content;
var initTimeDropDown = function (e) {
var i, hour, mins, value, content;
for (i=0; i<24*4; ++i) {
hour = parseInt(i/4, 10);
mins = ((i%4) * 15);
value = i * 15;
content = hour + ':' + (mins || '00');
e.options[i] = new Option(content, value);
}
},
for (i = 0; i < 24 * 4; ++i) {
hour = parseInt(i / 4, 10);
mins = ((i % 4) * 15);
value = i * 15;
content = hour + ':' + (mins || '00');
e.options[i] = new Option(content, value);
}
};
onPortChecked = function(response)
{
var is_open = response['arguments']['port-is-open'],
text = 'Port is <b>' + (is_open ? 'Open' : 'Closed') + '</b>',
e = data.elements.root.find('#port-label');
setInnerHTML(e[0],text);
},
var onPortChecked = function (response) {
var is_open = response['arguments']['port-is-open'];
var text = 'Port is <b>' + (is_open ? 'Open' : 'Closed') + '</b>';
var e = data.elements.root.find('#port-label');
setInnerHTML(e[0], text);
};
setGroupEnabled = function(parent_key, enabled)
{
var i, key, keys, root;
var setGroupEnabled = function (parent_key, enabled) {
var i, key, keys, root;
if (parent_key in data.groups)
{
root = data.elements.root,
keys = data.groups[parent_key];
if (parent_key in data.groups) {
root = data.elements.root;
keys = data.groups[parent_key];
for (i=0; key=keys[i]; ++i)
root.find('#'+key).attr('disabled',!enabled);
}
},
for (i = 0; key = keys[i]; ++i) {
root.find('#' + key).attr('disabled', !enabled);
};
};
};
onBlocklistUpdateClicked = function ()
{
data.remote.updateBlocklist();
setBlocklistButtonEnabled(false);
},
setBlocklistButtonEnabled = function(b)
{
var e = data.elements.blocklist_button;
e.attr('disabled',!b);
e.val(b ? 'Update' : 'Updating...');
},
var onBlocklistUpdateClicked = function () {
data.remote.updateBlocklist();
setBlocklistButtonEnabled(false);
};
getValue = function(e)
{
var str;
var setBlocklistButtonEnabled = function (b) {
var e = data.elements.blocklist_button;
e.attr('disabled', !b);
e.val(b ? 'Update' : 'Updating...');
};
switch (e[0].type)
{
case 'checkbox':
case 'radio':
return e.prop('checked');
var getValue = function (e) {
var str;
case 'text':
case 'url':
case 'email':
case 'number':
case 'search':
case 'select-one':
str = e.val();
if( parseInt(str,10).toString() === str)
return parseInt(str,10);
if( parseFloat(str).toString() === str)
return parseFloat(str);
return str;
switch (e[0].type) {
case 'checkbox':
case 'radio':
return e.prop('checked');
default:
return null;
}
},
case 'text':
case 'url':
case 'email':
case 'number':
case 'search':
case 'select-one':
str = e.val();
if (parseInt(str, 10).toString() === str) {
return parseInt(str, 10);
};
if (parseFloat(str).toString() === str) {
return parseFloat(str);
};
return str;
/* this callback is for controls whose changes can be applied
immediately, like checkboxs, radioboxes, and selects */
onControlChanged = function(ev)
{
var o = {};
o[ev.target.id] = getValue($(ev.target));
data.remote.savePrefs(o);
},
default:
return null;
}
};
/* these two callbacks are for controls whose changes can't be applied
immediately -- like a text entry field -- because it takes many
change events for the user to get to the desired result */
onControlFocused = function(ev)
{
data.oldValue = getValue($(ev.target));
},
onControlBlurred = function(ev)
{
var newValue = getValue($(ev.target));
if (newValue !== data.oldValue)
{
var o = {};
o[ev.target.id] = newValue;
data.remote.savePrefs(o);
delete data.oldValue;
}
},
/* this callback is for controls whose changes can be applied
immediately, like checkboxs, radioboxes, and selects */
var onControlChanged = function (ev) {
var o = {};
o[ev.target.id] = getValue($(ev.target));
data.remote.savePrefs(o);
};
getDefaultMobileOptions = function()
{
return {
width: $(window).width(),
height: $(window).height(),
position: [ 'left', 'top' ]
};
},
/* these two callbacks are for controls whose changes can't be applied
immediately -- like a text entry field -- because it takes many
change events for the user to get to the desired result */
var onControlFocused = function (ev) {
data.oldValue = getValue($(ev.target));
};
initialize = function (remote)
{
var i, key, e, o;
var onControlBlurred = function (ev) {
var newValue = getValue($(ev.target));
if (newValue !== data.oldValue) {
var o = {};
o[ev.target.id] = newValue;
data.remote.savePrefs(o);
delete data.oldValue;
}
};
data.remote = remote;
var getDefaultMobileOptions = function () {
return {
width: $(window).width(),
height: $(window).height(),
position: ['left', 'top']
};
};
e = $('#prefs-dialog');
data.elements.root = e;
var initialize = function (remote) {
var i, key, e, o;
initTimeDropDown(e.find('#alt-speed-time-begin')[0]);
initTimeDropDown(e.find('#alt-speed-time-end')[0]);
data.remote = remote;
o = isMobileDevice
? getDefaultMobileOptions()
: { width: 350, height: 400 };
o.autoOpen = false;
o.show = o.hide = 'fade';
o.close = onDialogClosed;
e.tabbedDialog(o);
e = $('#prefs-dialog');
data.elements.root = e;
e = e.find('#blocklist-update-button');
data.elements.blocklist_button = e;
e.click(onBlocklistUpdateClicked);
initTimeDropDown(e.find('#alt-speed-time-begin')[0]);
initTimeDropDown(e.find('#alt-speed-time-end')[0]);
// listen for user input
for (i=0; key=data.keys[i]; ++i)
{
e = data.elements.root.find('#'+key);
switch (e[0].type)
{
case 'checkbox':
case 'radio':
case 'select-one':
e.change(onControlChanged);
break;
o = isMobileDevice ? getDefaultMobileOptions() : {
width: 350,
height: 400
};
o.autoOpen = false;
o.show = o.hide = 'fade';
o.close = onDialogClosed;
e.tabbedDialog(o);
case 'text':
case 'url':
case 'email':
case 'number':
case 'search':
e.focus(onControlFocused);
e.blur(onControlBlurred);
e = e.find('#blocklist-update-button');
data.elements.blocklist_button = e;
e.click(onBlocklistUpdateClicked);
default:
break;
}
}
},
// listen for user input
for (i = 0; key = data.keys[i]; ++i) {
e = data.elements.root.find('#' + key);
switch (e[0].type) {
case 'checkbox':
case 'radio':
case 'select-one':
e.change(onControlChanged);
break;
getValues = function()
{
var i, key, val, o={},
keys = data.keys,
root = data.elements.root;
case 'text':
case 'url':
case 'email':
case 'number':
case 'search':
e.focus(onControlFocused);
e.blur(onControlBlurred);
for (i=0; key=keys[i]; ++i) {
val = getValue(root.find('#'+key));
if (val !== null)
o[key] = val;
}
default:
break;
};
};
};
return o;
},
var getValues = function () {
var i, key, val, o = {},
keys = data.keys,
root = data.elements.root;
onDialogClosed = function()
{
transmission.hideMobileAddressbar();
for (i = 0; key = keys[i]; ++i) {
val = getValue(root.find('#' + key));
if (val !== null) {
o[key] = val;
};
};
$(data.dialog).trigger('closed', getValues());
};
return o;
};
/****
***** PUBLIC FUNCTIONS
****/
var onDialogClosed = function () {
transmission.hideMobileAddressbar();
// update the dialog's controls
this.set = function (o)
{
var e, i, key, val, option,
keys = data.keys,
root = data.elements.root;
$(data.dialog).trigger('closed', getValues());
};
setBlocklistButtonEnabled(true);
/****
***** PUBLIC FUNCTIONS
****/
for (i=0; key=keys[i]; ++i)
{
val = o[key];
e = root.find('#'+key);
// update the dialog's controls
this.set = function (o) {
var e, i, key, val, option;
var keys = data.keys;
var root = data.elements.root;
if (key === 'blocklist-size')
{
// special case -- regular text area
e.text('' + val.toStringWithCommas());
}
else switch (e[0].type)
{
case 'checkbox':
case 'radio':
e.prop('checked', val);
setGroupEnabled(key, val);
break;
case 'text':
case 'url':
case 'email':
case 'number':
case 'search':
// don't change the text if the user's editing it.
// it's very annoying when that happens!
if (e[0] !== document.activeElement)
e.val(val);
break;
case 'select-one':
e.val(val);
break;
default:
break;
}
}
};
setBlocklistButtonEnabled(true);
this.show = function ()
{
transmission.hideMobileAddressbar();
for (i = 0; key = keys[i]; ++i) {
val = o[key];
e = root.find('#' + key);
setBlocklistButtonEnabled(true);
data.remote.checkPort(onPortChecked,this);
data.elements.root.dialog('open');
};
if (key === 'blocklist-size') {
// special case -- regular text area
e.text('' + val.toStringWithCommas());
} else switch (e[0].type) {
case 'checkbox':
case 'radio':
e.prop('checked', val);
setGroupEnabled(key, val);
break;
case 'text':
case 'url':
case 'email':
case 'number':
case 'search':
// don't change the text if the user's editing it.
// it's very annoying when that happens!
if (e[0] !== document.activeElement) {
e.val(val);
};
break;
case 'select-one':
e.val(val);
break;
default:
break;
};
};
};
this.close = function ()
{
transmission.hideMobileAddressbar();
data.elements.root.dialog('close');
},
this.show = function () {
transmission.hideMobileAddressbar();
this.shouldAddedTorrentsStart = function()
{
return data.elements.root.find('#start-added-torrents')[0].checked;
};
setBlocklistButtonEnabled(true);
data.remote.checkPort(onPortChecked, this);
data.elements.root.dialog('open');
};
data.dialog = this;
initialize (remote);
this.close = function () {
transmission.hideMobileAddressbar();
data.elements.root.dialog('close');
};
this.shouldAddedTorrentsStart = function () {
return data.elements.root.find('#start-added-torrents')[0].checked;
};
data.dialog = this;
initialize(remote);
};

View File

@ -6,266 +6,283 @@
*/
var RPC = {
_DaemonVersion : 'version',
_DownSpeedLimit : 'speed-limit-down',
_DownSpeedLimited : 'speed-limit-down-enabled',
_QueueMoveTop : 'queue-move-top',
_QueueMoveBottom : 'queue-move-bottom',
_QueueMoveUp : 'queue-move-up',
_QueueMoveDown : 'queue-move-down',
_Root : '../rpc',
_TurtleDownSpeedLimit : 'alt-speed-down',
_TurtleState : 'alt-speed-enabled',
_TurtleUpSpeedLimit : 'alt-speed-up',
_UpSpeedLimit : 'speed-limit-up',
_UpSpeedLimited : 'speed-limit-up-enabled'
_DaemonVersion: 'version',
_DownSpeedLimit: 'speed-limit-down',
_DownSpeedLimited: 'speed-limit-down-enabled',
_QueueMoveTop: 'queue-move-top',
_QueueMoveBottom: 'queue-move-bottom',
_QueueMoveUp: 'queue-move-up',
_QueueMoveDown: 'queue-move-down',
_Root: '../rpc',
_TurtleDownSpeedLimit: 'alt-speed-down',
_TurtleState: 'alt-speed-enabled',
_TurtleUpSpeedLimit: 'alt-speed-up',
_UpSpeedLimit: 'speed-limit-up',
_UpSpeedLimited: 'speed-limit-up-enabled'
};
function TransmissionRemote(controller)
{
this.initialize(controller);
return this;
function TransmissionRemote(controller) {
this.initialize(controller);
return this;
}
TransmissionRemote.prototype =
{
/*
* Constructor
*/
initialize: function(controller) {
this._controller = controller;
this._error = '';
this._token = '';
},
TransmissionRemote.prototype = {
/*
* Constructor
*/
initialize: function (controller) {
this._controller = controller;
this._error = '';
this._token = '';
},
/*
* Display an error if an ajax request fails, and stop sending requests
* or on a 409, globally set the X-Transmission-Session-Id and resend
*/
ajaxError: function(request, error_string, exception, ajaxObject) {
var token,
remote = this;
/*
* Display an error if an ajax request fails, and stop sending requests
* or on a 409, globally set the X-Transmission-Session-Id and resend
*/
ajaxError: function (request, error_string, exception, ajaxObject) {
var token;
var remote = this;
// set the Transmission-Session-Id on a 409
if (request.status === 409 && (token = request.getResponseHeader('X-Transmission-Session-Id'))){
remote._token = token;
$.ajax(ajaxObject);
return;
}
// set the Transmission-Session-Id on a 409
if (request.status === 409 && (token = request.getResponseHeader('X-Transmission-Session-Id'))) {
remote._token = token;
$.ajax(ajaxObject);
return;
};
remote._error = request.responseText
? request.responseText.trim().replace(/(<([^>]+)>)/ig,"")
: "";
if (!remote._error.length)
remote._error = 'Server not responding';
remote._error = request.responseText ? request.responseText.trim().replace(/(<([^>]+)>)/ig, "") : "";
if (!remote._error.length) {
remote._error = 'Server not responding';
};
dialog.confirm('Connection Failed',
'Could not connect to the server. You may need to reload the page to reconnect.',
'Details',
function() {
alert(remote._error);
},
'Dismiss');
remote._controller.togglePeriodicSessionRefresh(false);
},
dialog.confirm('Connection Failed',
'Could not connect to the server. You may need to reload the page to reconnect.',
'Details',
function () {
alert(remote._error);
},
'Dismiss');
remote._controller.togglePeriodicSessionRefresh(false);
},
appendSessionId: function(XHR) {
if (this._token) {
XHR.setRequestHeader('X-Transmission-Session-Id', this._token);
}
},
appendSessionId: function (XHR) {
if (this._token) {
XHR.setRequestHeader('X-Transmission-Session-Id', this._token);
};
},
sendRequest: function(data, callback, context, async) {
var remote = this;
if (typeof async != 'boolean')
async = true;
sendRequest: function (data, callback, context, async) {
var remote = this;
if (typeof async != 'boolean') {
async = true;
};
var ajaxSettings = {
url: RPC._Root,
type: 'POST',
contentType: 'json',
dataType: 'json',
cache: false,
data: JSON.stringify(data),
beforeSend: function(XHR){ remote.appendSessionId(XHR); },
error: function(request, error_string, exception){ remote.ajaxError(request, error_string, exception, ajaxSettings); },
success: callback,
context: context,
async: async
};
var ajaxSettings = {
url: RPC._Root,
type: 'POST',
contentType: 'json',
dataType: 'json',
cache: false,
data: JSON.stringify(data),
beforeSend: function (XHR) {
remote.appendSessionId(XHR);
},
error: function (request, error_string, exception) {
remote.ajaxError(request, error_string, exception, ajaxSettings);
},
success: callback,
context: context,
async: async
};
$.ajax(ajaxSettings);
},
$.ajax(ajaxSettings);
},
loadDaemonPrefs: function(callback, context, async) {
var o = { method: 'session-get' };
this.sendRequest(o, callback, context, async);
},
loadDaemonPrefs: function (callback, context, async) {
var o = {
method: 'session-get'
};
this.sendRequest(o, callback, context, async);
},
checkPort: function(callback, context, async) {
var o = { method: 'port-test' };
this.sendRequest(o, callback, context, async);
},
checkPort: function (callback, context, async) {
var o = {
method: 'port-test'
};
this.sendRequest(o, callback, context, async);
},
renameTorrent: function(torrentIds, oldpath, newname, callback, context) {
var o = {
method: 'torrent-rename-path',
arguments: {
'ids': torrentIds,
'path': oldpath,
'name': newname
}
};
this.sendRequest(o, callback, context);
},
renameTorrent: function (torrentIds, oldpath, newname, callback, context) {
var o = {
method: 'torrent-rename-path',
arguments: {
'ids': torrentIds,
'path': oldpath,
'name': newname
}
};
this.sendRequest(o, callback, context);
},
loadDaemonStats: function(callback, context, async) {
var o = { method: 'session-stats' };
this.sendRequest(o, callback, context, async);
},
loadDaemonStats: function (callback, context, async) {
var o = {
method: 'session-stats'
};
this.sendRequest(o, callback, context, async);
},
updateTorrents: function(torrentIds, fields, callback, context) {
var o = {
method: 'torrent-get',
arguments: {
'fields': fields
}
};
if (torrentIds)
o['arguments'].ids = torrentIds;
this.sendRequest(o, function(response) {
var args = response['arguments'];
callback.call(context,args.torrents,args.removed);
});
},
updateTorrents: function (torrentIds, fields, callback, context) {
var o = {
method: 'torrent-get',
arguments: {
'fields': fields
}
};
if (torrentIds) {
o['arguments'].ids = torrentIds;
};
this.sendRequest(o, function (response) {
var args = response['arguments'];
callback.call(context, args.torrents, args.removed);
});
},
getFreeSpace: function(dir, callback, context) {
var remote = this;
var o = {
method: 'free-space',
arguments: { path: dir }
};
this.sendRequest(o, function(response) {
var args = response['arguments'];
callback.call (context, args.path, args['size-bytes']);
});
},
getFreeSpace: function (dir, callback, context) {
var remote = this;
var o = {
method: 'free-space',
arguments: {
path: dir
}
};
this.sendRequest(o, function (response) {
var args = response['arguments'];
callback.call(context, args.path, args['size-bytes']);
});
},
changeFileCommand: function(torrentId, fileIndices, command) {
var remote = this,
args = { ids: [torrentId] };
args[command] = fileIndices;
this.sendRequest({
arguments: args,
method: 'torrent-set'
}, function() {
remote._controller.refreshTorrents([torrentId]);
});
},
changeFileCommand: function (torrentId, fileIndices, command) {
var remote = this,
args = {
ids: [torrentId]
};
args[command] = fileIndices;
this.sendRequest({
arguments: args,
method: 'torrent-set'
}, function () {
remote._controller.refreshTorrents([torrentId]);
});
},
sendTorrentSetRequests: function(method, torrent_ids, args, callback, context) {
if (!args) args = { };
args['ids'] = torrent_ids;
var o = {
method: method,
arguments: args
};
this.sendRequest(o, callback, context);
},
sendTorrentSetRequests: function (method, torrent_ids, args, callback, context) {
if (!args) {
args = {};
};
args['ids'] = torrent_ids;
var o = {
method: method,
arguments: args
};
this.sendRequest(o, callback, context);
},
sendTorrentActionRequests: function(method, torrent_ids, callback, context) {
this.sendTorrentSetRequests(method, torrent_ids, null, callback, context);
},
sendTorrentActionRequests: function (method, torrent_ids, callback, context) {
this.sendTorrentSetRequests(method, torrent_ids, null, callback, context);
},
startTorrents: function(torrent_ids, noqueue, callback, context) {
var name = noqueue ? 'torrent-start-now' : 'torrent-start';
this.sendTorrentActionRequests(name, torrent_ids, callback, context);
},
stopTorrents: function(torrent_ids, callback, context) {
this.sendTorrentActionRequests('torrent-stop', torrent_ids, callback, context);
},
startTorrents: function (torrent_ids, noqueue, callback, context) {
var name = noqueue ? 'torrent-start-now' : 'torrent-start';
this.sendTorrentActionRequests(name, torrent_ids, callback, context);
},
stopTorrents: function (torrent_ids, callback, context) {
this.sendTorrentActionRequests('torrent-stop', torrent_ids, callback, context);
},
moveTorrents: function(torrent_ids, new_location, callback, context) {
var remote = this;
this.sendTorrentSetRequests( 'torrent-set-location', torrent_ids,
{"move": true, "location": new_location}, callback, context);
},
moveTorrents: function (torrent_ids, new_location, callback, context) {
var remote = this;
this.sendTorrentSetRequests('torrent-set-location', torrent_ids, {
"move": true,
"location": new_location
}, callback, context);
},
removeTorrents: function(torrent_ids, callback, context) {
this.sendTorrentActionRequests('torrent-remove', torrent_ids, callback, context);
},
removeTorrentsAndData: function(torrents) {
var remote = this;
var o = {
method: 'torrent-remove',
arguments: {
'delete-local-data': true,
ids: [ ]
}
};
removeTorrents: function (torrent_ids, callback, context) {
this.sendTorrentActionRequests('torrent-remove', torrent_ids, callback, context);
},
removeTorrentsAndData: function (torrents) {
var remote = this;
var o = {
method: 'torrent-remove',
arguments: {
'delete-local-data': true,
ids: []
}
};
if (torrents) {
for (var i=0, len=torrents.length; i<len; ++i) {
o.arguments.ids.push(torrents[i].getId());
}
}
this.sendRequest(o, function() {
remote._controller.refreshTorrents();
});
},
verifyTorrents: function(torrent_ids, callback, context) {
this.sendTorrentActionRequests('torrent-verify', torrent_ids, callback, context);
},
reannounceTorrents: function(torrent_ids, callback, context) {
this.sendTorrentActionRequests('torrent-reannounce', torrent_ids, callback, context);
},
addTorrentByUrl: function(url, options) {
var remote = this;
if (url.match(/^[0-9a-f]{40}$/i)) {
url = 'magnet:?xt=urn:btih:'+url;
}
var o = {
method: 'torrent-add',
arguments: {
paused: (options.paused),
filename: url
}
};
this.sendRequest(o, function() {
remote._controller.refreshTorrents();
});
},
savePrefs: function(args) {
var remote = this;
var o = {
method: 'session-set',
arguments: args
};
this.sendRequest(o, function() {
remote._controller.loadDaemonPrefs();
});
},
updateBlocklist: function() {
var remote = this;
var o = {
method: 'blocklist-update'
};
this.sendRequest(o, function() {
remote._controller.loadDaemonPrefs();
});
},
if (torrents) {
for (var i = 0, len = torrents.length; i < len; ++i) {
o.arguments.ids.push(torrents[i].getId());
};
};
this.sendRequest(o, function () {
remote._controller.refreshTorrents();
});
},
verifyTorrents: function (torrent_ids, callback, context) {
this.sendTorrentActionRequests('torrent-verify', torrent_ids, callback, context);
},
reannounceTorrents: function (torrent_ids, callback, context) {
this.sendTorrentActionRequests('torrent-reannounce', torrent_ids, callback, context);
},
addTorrentByUrl: function (url, options) {
var remote = this;
if (url.match(/^[0-9a-f]{40}$/i)) {
url = 'magnet:?xt=urn:btih:' + url;
}
var o = {
method: 'torrent-add',
arguments: {
paused: (options.paused),
filename: url
}
};
this.sendRequest(o, function () {
remote._controller.refreshTorrents();
});
},
savePrefs: function (args) {
var remote = this;
var o = {
method: 'session-set',
arguments: args
};
this.sendRequest(o, function () {
remote._controller.loadDaemonPrefs();
});
},
updateBlocklist: function () {
var remote = this;
var o = {
method: 'blocklist-update'
};
this.sendRequest(o, function () {
remote._controller.loadDaemonPrefs();
});
},
// Added queue calls
moveTorrentsToTop: function(torrent_ids, callback, context) {
this.sendTorrentActionRequests(RPC._QueueMoveTop, torrent_ids, callback, context);
},
moveTorrentsToBottom: function(torrent_ids, callback, context) {
this.sendTorrentActionRequests(RPC._QueueMoveBottom, torrent_ids, callback, context);
},
moveTorrentsUp: function(torrent_ids, callback, context) {
this.sendTorrentActionRequests(RPC._QueueMoveUp, torrent_ids, callback, context);
},
moveTorrentsDown: function(torrent_ids, callback, context) {
this.sendTorrentActionRequests(RPC._QueueMoveDown, torrent_ids, callback, context);
}
// Added queue calls
moveTorrentsToTop: function (torrent_ids, callback, context) {
this.sendTorrentActionRequests(RPC._QueueMoveTop, torrent_ids, callback, context);
},
moveTorrentsToBottom: function (torrent_ids, callback, context) {
this.sendTorrentActionRequests(RPC._QueueMoveBottom, torrent_ids, callback, context);
},
moveTorrentsUp: function (torrent_ids, callback, context) {
this.sendTorrentActionRequests(RPC._QueueMoveUp, torrent_ids, callback, context);
},
moveTorrentsDown: function (torrent_ids, callback, context) {
this.sendTorrentActionRequests(RPC._QueueMoveDown, torrent_ids, callback, context);
}
};

View File

@ -5,405 +5,401 @@
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*/
function TorrentRendererHelper()
{
}
function TorrentRendererHelper() {}
TorrentRendererHelper.getProgressInfo = function(controller, t)
{
var pct, extra,
s = t.getStatus(),
seed_ratio_limit = t.seedRatioLimit(controller);
TorrentRendererHelper.getProgressInfo = function (controller, t) {
var pct, extra;
var s = t.getStatus();
var 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 (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 = '';
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(' ')
};
return {
percent: pct,
complete: ['torrent_progress_bar', 'complete', extra].join(' '),
incomplete: ['torrent_progress_bar', 'incomplete', extra].join(' ')
};
};
TorrentRendererHelper.createProgressbar = function(classes)
{
var complete, incomplete, progressbar;
TorrentRendererHelper.createProgressbar = function (classes) {
var complete, incomplete, progressbar;
complete = document.createElement('div');
complete.className = 'torrent_progress_bar complete';
complete = document.createElement('div');
complete.className = 'torrent_progress_bar complete';
incomplete = document.createElement('div');
incomplete.className = 'torrent_progress_bar incomplete';
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);
progressbar = document.createElement('div');
progressbar.className = 'torrent_progress_bar_container ' + classes;
progressbar.appendChild(complete);
progressbar.appendChild(incomplete);
return { 'element': progressbar, 'complete': complete, 'incomplete': incomplete };
return {
'element': progressbar,
'complete': complete,
'incomplete': incomplete
};
};
TorrentRendererHelper.renderProgressbar = function(controller, t, progressbar)
{
var e, style, width, display,
info = TorrentRendererHelper.getProgressInfo(controller, t);
TorrentRendererHelper.renderProgressbar = function (controller, t, progressbar) {
var e, style, width, display
var 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 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
});
};
// 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;
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.formatUL = function (t) {
return '↑ ' + Transmission.fmt.speedBps(t.getUploadSpeed());
};
TorrentRendererHelper.formatDL = function(t)
{
return '↓ ' + Transmission.fmt.speedBps(t.getDownloadSpeed());
TorrentRendererHelper.formatDL = function (t) {
return '↓ ' + Transmission.fmt.speedBps(t.getDownloadSpeed());
};
/****
*****
*****
****/
*****
*****
****/
function TorrentRendererFull()
{
}
TorrentRendererFull.prototype =
{
createRow: function()
{
var root, name, peers, progressbar, details, image, button;
function TorrentRendererFull() {};
TorrentRendererFull.prototype = {
createRow: function () {
var root, name, peers, progressbar, details, image, button;
root = document.createElement('li');
root.className = 'torrent';
root = document.createElement('li');
root.className = 'torrent';
name = document.createElement('div');
name.className = 'torrent_name';
name = document.createElement('div');
name.className = 'torrent_name';
peers = document.createElement('div');
peers.className = 'torrent_peer_details';
peers = document.createElement('div');
peers.className = 'torrent_peer_details';
progressbar = TorrentRendererHelper.createProgressbar('full');
progressbar = TorrentRendererHelper.createProgressbar('full');
details = document.createElement('div');
details.className = 'torrent_progress_details';
details = document.createElement('div');
details.className = 'torrent_progress_details';
image = document.createElement('div');
button = document.createElement('a');
button.appendChild(image);
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.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;
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;
},
return root;
},
getPeerDetails: function(t)
{
var err,
peer_count,
webseed_count,
fmt = Transmission.fmt;
getPeerDetails: function (t) {
var err,
peer_count,
webseed_count,
fmt = Transmission.fmt;
if ((err = t.getErrorMessage()))
return err;
if ((err = t.getErrorMessage())) {
return err;
};
if (t.isDownloading())
{
peer_count = t.getPeersConnected();
webseed_count = t.getWebseedsSendingToUs();
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 (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.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('');
if (t.isChecking()) {
return ['Verifying local data (', Transmission.fmt.percentString(100.0 * t.getRecheckProgress()), '% tested)'].join('');
}
return t.getStateString();
},
return t.getStateString();
},
getProgressDetails: function(controller, t)
{
if (t.needsMetaData()) {
var MetaDataStatus = "retrieving";
if (t.isStopped())
MetaDataStatus = "needs";
var percent = 100 * t.getMetadataPercentComplete();
return [ "Magnetized transfer - " + MetaDataStatus + " metadata (",
Transmission.fmt.percentString(percent),
"%)" ].join('');
}
getProgressDetails: function (controller, t) {
if (t.needsMetaData()) {
var MetaDataStatus = "retrieving";
if (t.isStopped()) {
MetaDataStatus = "needs";
};
var percent = 100 * t.getMetadataPercentComplete();
return ["Magnetized transfer - " + MetaDataStatus + " metadata (",
Transmission.fmt.percentString(percent),
"%)"
].join('');
}
var c,
sizeWhenDone = t.getSizeWhenDone(),
totalSize = t.getTotalSize(),
is_done = t.isDone() || t.isSeeding();
var c;
var sizeWhenDone = t.getSizeWhenDone();
var totalSize = t.getTotalSize();
var 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(), '%)' ];
}
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(' - ');
var 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');
}
// maybe append eta
if (!t.isStopped() && (!is_done || t.seedRatioLimit(controller) > 0)) {
c.push(' - ');
var 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('');
},
return c.join('');
},
render: function(controller, t, root)
{
// name
setTextContent(root._name_container, t.getName());
render: function (controller, t, root) {
// name
setTextContent(root._name_container, t.getName());
// progressbar
TorrentRendererHelper.renderProgressbar(controller, t, root._progressbar);
// progressbar
TorrentRendererHelper.renderProgressbar(controller, t, root._progressbar);
// peer details
var has_error = t.getError() !== Torrent._ErrNone;
var e = root._peer_details_container;
$(e).toggleClass('error',has_error);
setTextContent(e, this.getPeerDetails(t));
// peer details
var has_error = t.getError() !== Torrent._ErrNone;
var 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));
// progress details
e = root._progress_details_container;
setTextContent(e, this.getProgressDetails(controller, t));
// pause/resume button
var is_stopped = t.isStopped();
e = root._pause_resume_button_image;
e.alt = is_stopped ? 'Resume' : 'Pause';
e.className = is_stopped ? 'torrent_resume' : 'torrent_pause';
}
// pause/resume button
var is_stopped = t.isStopped();
e = root._pause_resume_button_image;
e.alt = is_stopped ? 'Resume' : 'Pause';
e.className = is_stopped ? 'torrent_resume' : 'torrent_pause';
}
};
/****
*****
*****
****/
*****
*****
****/
function TorrentRendererCompact()
{
}
TorrentRendererCompact.prototype =
{
createRow: function()
{
var progressbar, details, name, root;
function TorrentRendererCompact() {};
TorrentRendererCompact.prototype = {
createRow: function () {
var progressbar, details, name, root;
progressbar = TorrentRendererHelper.createProgressbar('compact');
progressbar = TorrentRendererHelper.createProgressbar('compact');
details = document.createElement('div');
details.className = 'torrent_peer_details compact';
details = document.createElement('div');
details.className = 'torrent_peer_details compact';
name = document.createElement('div');
name.className = 'torrent_name 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;
},
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)
{
var c;
if ((c = t.getErrorMessage()))
return c;
if (t.isDownloading()) {
var have_dn = t.getDownloadSpeed() > 0,
have_up = t.getUploadSpeed() > 0;
if (!have_up && !have_dn)
return 'Idle';
var s = '';
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();
},
getPeerDetails: function (t) {
var c;
if ((c = t.getErrorMessage())) {
return c;
};
if (t.isDownloading()) {
var have_dn = t.getDownloadSpeed() > 0;
var have_up = t.getUploadSpeed() > 0;
render: function(controller, t, root)
{
// name
var is_stopped = t.isStopped();
var e = root._name_container;
$(e).toggleClass('paused', is_stopped);
setTextContent(e, t.getName());
if (!have_up && !have_dn) {
return 'Idle';
};
var s = '';
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();
},
// peer details
var has_error = t.getError() !== Torrent._ErrNone;
e = root._details_container;
$(e).toggleClass('error', has_error);
setTextContent(e, this.getPeerDetails(t));
render: function (controller, t, root) {
// name
var is_stopped = t.isStopped();
var e = root._name_container;
$(e).toggleClass('paused', is_stopped);
setTextContent(e, t.getName());
// progressbar
TorrentRendererHelper.renderProgressbar(controller, t, root._progressbar);
}
// peer details
var 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) {
var 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) {
var 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();
}
function TorrentRow(view, controller, torrent) {
this.initialize(view, controller, torrent);
};
TorrentRow.prototype = {
initialize: function (view, controller, torrent) {
var 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) {
var 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();
}
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff