move away from the monolithic file approach and split out into smaller

more managable files. begin implementation of a javascript gettext.
this may break some things in the ajax ui.
This commit is contained in:
Damien Churchill 2008-09-22 12:46:12 +00:00
parent cf6266e545
commit a412547584
11 changed files with 1427 additions and 1289 deletions

View File

@ -1,7 +1,7 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Deluge: AJAX UI (alpha)</title>
<title>Deluge: AJAX UI (alpha) $version</title>
<link rel="icon" href="$base/static/images/deluge_icon.gif" type="image/gif" />
<link rel="shortcut icon" href="$base/static/images/deluge_icon.gif" type="image/gif" />
<link rel="stylesheet" type="text/css" href="$base/template/static/css/mooui.css" />
@ -10,8 +10,15 @@
<script src="$base/template/static/js/mootools-1.2-more.js" type="text/javascript"></script>
<script src="$base/template/static/js/Rpc.js" type="text/javascript"></script>
<script src="$base/template/static/js/mooui.js" type="text/javascript"></script>
<script src="$base/template/static/js/deluge.widgets.js" type="text/javascript"></script>
<script src="$base/template/static/js/deluge.js" type="text/javascript"></script>
<script src="$base/template/render/js/deluge-strings.js" type="text/javascript"></script>
<script src="$base/template/static/js/deluge-menus.js" type="text/javascript"></script>
<script src="$base/template/static/js/deluge-add.js" type="text/javascript"></script>
<script src="$base/template/static/js/deluge-bars.js" type="text/javascript"></script>
<script src="$base/template/static/js/deluge-details.js" type="text/javascript"></script>
<script src="$base/template/static/js/deluge-preferences.js" type="text/javascript"></script>
<script src="$base/template/static/js/deluge-torrent-grid.js" type="text/javascript"></script>
<script src="$base/template/static/js/deluge-ui.js" type="text/javascript"></script>
</head>
<body>
<div id="overlay">

View File

@ -0,0 +1,26 @@
/*
* Script: deluge-strings.js
* A script file that is run through the template renderer in order for
* translated strings to be retrieved.
*
* Copyright:
* Damien Churchill (c) 2008
*/
Deluge.Strings = {
maps: {},
add: function(string, translation) {
this.maps[string] = translation;
},
get: function(string) {
if (this.maps[string]) {
return this.maps[string];
} else {
return string;
}
}
}
Deluge.Strings.add('Pause', '$_('Pause')');
Deluge.Strings.add('Resume', '$_('Resume')');
Deluge.Strings.add('Options', '$_('Options')');
Deluge.Strings.add('Torrents Window', '$_('Torrents Window')');

View File

@ -0,0 +1,32 @@
/*
* Script: deluge-add.js
* Contains the add torrent window and (eventually) the torrent creator
*
* Copyright:
* Damien Churchill (c) 2008
*/
Deluge.Widgets.AddWindow = new Class({
Extends: Widgets.Window,
options: {
width: 400,
height: 200,
title: 'Add Torrents',
url: '/template/render/html/window_add_torrent.html'
},
initialize: function() {
this.parent();
this.addEvent('loaded', this.loaded.bindWithEvent(this));
},
loaded: function(event) {
this.formfile = this.content.getChildren()[0];
this.formurl = this.content.getChildren()[1];
this.formurl.addEvent('submit', function(e) {
e.stop();
Deluge.Client.add_torrent_url(this.formurl.url.value, {});
this.hide();
}.bindWithEvent(this))
}
});

View File

@ -0,0 +1,122 @@
/*
* Script: deluge-bars.js
* Contains the various bars (Sidebar, Toolbar, Statusbar) used within deluge
*
* Copyright:
* Damien Churchill (c) 2008
*/
Deluge.Widgets.Toolbar = new Class({
Implements: Events,
Extends: Widgets.Base,
initialize: function() {
this.parent($('toolbar'))
this.buttons = this.element.getFirst()
this.info = this.element.getLast()
this.buttons.getElements('li').each(function(el) {
el.addEvent('click', function(e) {
e.action = el.id
this.fireEvent('buttonClick', e)
}.bind(this))
}, this)
}
});
Deluge.Widgets.StatusBar = new Class({
Extends: Widgets.Base,
initialize: function() {
this.parent($('status'));
this.element.getElements('li').each(function(el) {
this[el.id] = el;
}, this);
},
update: function(stats) {
this.connections.set('text', stats.num_connections);
this.downspeed.set('text', stats.download_rate.toSpeed());
this.upspeed.set('text', stats.upload_rate.toSpeed());
this.dht.set('text', stats.dht_nodes);
}
});
Deluge.Widgets.Labels = new Class({
Extends: Widgets.Base,
regex: /([\w]+)\s\((\d)\)/,
initialize: function() {
this.parent($('labels'))
this.bound = {
resized: this.resized.bindWithEvent(this),
clickedState: this.clickedState.bindWithEvent(this)
}
this.list = new Element('ul')
this.element.grab(this.list)
this.addStates()
this.state = 'All'
this.islabels = false;
this.addEvent('resize', this.resized)
},
addStates: function() {
this.list.grab(new Element('li').set('text', 'All').addClass('all').addClass('activestate'))
this.list.grab(new Element('li').set('text', 'Downloading').addClass('downloading'))
this.list.grab(new Element('li').set('text', 'Seeding').addClass('seeding'))
this.list.grab(new Element('li').set('text', 'Queued').addClass('queued'))
this.list.grab(new Element('li').set('text', 'Paused').addClass('paused'))
this.list.grab(new Element('li').set('text', 'Error').addClass('error'))
this.list.grab(new Element('li').set('text', 'Checking').addClass('checking'))
this.list.grab(new Element('hr'))
},
addLabel: function(name) {
},
clickedState: function(e) {
if (this.islabels) {
var old = this.list.getElement('.' + this.state.toLowerCase())
old.removeClass('activestate')
this.state = e.target.get('text').match(/^(\w+)/)[1]
e.target.addClass('activestate')
this.fireEvent('stateChanged', this.state)
} else {
}
},
update: function(filters) {
if (filters.state.length == 1)
this.updateNoLabels(filters);
else
this.updateLabels(filters)
},
updateNoLabels: function(filters) {
this.islabels = false;
},
updateLabels: function(filters) {
this.islabels = true;
$each(filters.state, function(state) {
var el = this.list.getElement('.' + state[0].toLowerCase())
if (!el) return
el.set('text', state[0] + ' (' + state[1] + ')')
el.removeEvent('click', this.bound.clickedState)
el.addEvent('click', this.bound.clickedState)
}, this)
},
resized: function(event) {
var height = this.element.getInnerSize().y;
this.list.getSizeModifiers();
height -= this.list.modifiers.y;
this.list.setStyle('height', height)
}
});

View File

@ -0,0 +1,448 @@
/*
* Script: deluge-details.js
* Contains the tabs for the torrent details
*
* Copyright:
* Damien Churchill (c) 2008
*/
Deluge.Widgets.Details = new Class({
Extends: Widgets.Tabs,
initialize: function() {
this.parent($$('#details .mooui-tabs')[0])
this.statistics = new Deluge.Widgets.StatisticsPage()
this.details = new Deluge.Widgets.DetailsPage()
this.files = new Deluge.Widgets.FilesPage()
this.peers = new Deluge.Widgets.PeersPage()
this.options = new Deluge.Widgets.OptionsPage()
this.addPage(this.statistics)
this.addPage(this.details)
this.addPage(this.files)
this.addPage(this.peers)
this.addPage(this.options)
this.addEvent('pageChanged', function(e) {
this.update(this.torrentId);
}.bindWithEvent(this));
this.addEvent('resize', this.resized.bindWithEvent(this))
this.files.addEvent('menuAction', function(e) {
files = []
this.files.grid.get_selected().each(function(file) {
files.push(file.fileIndex)
})
e.files = files
this.fireEvent('filesAction', e)
}.bindWithEvent(this))
},
keys: {
0: Deluge.Keys.Statistics,
1: Deluge.Keys.Details,
2: Deluge.Keys.Files,
3: Deluge.Keys.Peers,
4: Deluge.Keys.Options
},
update: function(torrentId) {
this.torrentId = torrentId
if (!this.torrentId) return
var keys = this.keys[this.currentPage], page = this.pages[this.currentPage];
Deluge.Client.get_torrent_status(torrentId, keys, {
onSuccess: function(torrent) {
torrent.id = torrentId
if (page.update) page.update(torrent)
}.bindWithEvent(this)
})
},
resized: function(event) {
this.pages.each(function(page) {
page.getSizeModifiers()
page.sets({
width: event.width - page.element.modifiers.x,
height: event.height - page.element.modifiers.y - 28
})
})
}
});
Deluge.Widgets.StatisticsPage = new Class({
Extends: Widgets.TabPage,
options: {
url: '/template/render/html/tab_statistics.html'
},
initialize: function() {
this.parent('Statistics')
},
update: function(torrent) {
var data = {
downloaded: torrent.total_done.toBytes()+' ('+torrent.total_payload_download.toBytes()+')',
uploaded: torrent.total_uploaded.toBytes()+' ('+torrent.total_payload_upload.toBytes()+')',
share: torrent.ratio.toFixed(3),
announce: torrent.next_announce.toTime(),
tracker_status: torrent.tracker_status,
downspeed: torrent.download_payload_rate.toSpeed(),
upspeed: torrent.upload_payload_rate.toSpeed(),
eta: torrent.eta.toTime(),
pieces: torrent.num_pieces + ' (' + torrent.piece_length.toBytes() + ')',
seeders: torrent.num_seeds + ' (' + torrent.total_seeds + ')',
peers: torrent.num_peers + ' (' + torrent.total_peers + ')',
avail: torrent.distributed_copies.toFixed(3),
active_time: torrent.active_time.toTime(),
seeding_time: torrent.seeding_time.toTime(),
seed_rank: torrent.seed_rank
}
if (torrent.is_auto_managed) {data.auto_managed = 'True'}
else {data.auto_managed = 'False'}
this.element.getElements('dd').each(function(item) {
item.set('text', data[item.getProperty('class')])
}, this)
}
})
Deluge.Widgets.DetailsPage = new Class({
Extends: Widgets.TabPage,
options: {
url: '/template/render/html/tab_details.html'
},
initialize: function() {
this.parent('Details')
},
update: function(torrent) {
var data = {
torrent_name: torrent.name,
hash: torrent.id,
path: torrent.save_path,
size: torrent.total_size.toBytes(),
files: torrent.num_files,
status: torrent.tracker_status,
tracker: torrent.tracker
}
this.element.getElements('dd').each(function(item) {
item.set('text', data[item.getProperty('class')])
}, this)
}
})
Deluge.Widgets.FilesGrid = new Class({
Extends: Widgets.DataGrid,
options: {
columns: [
{name: 'filename',text: 'Filename',type:'text',width: 350},
{name: 'size',text: 'Size',type:'bytes',width: 80},
{name: 'progress',text: 'Progress',type:'progress',width: 180},
{name: 'priority',text: 'Priority',type:'icon',width: 150}
]
},
priority_texts: {
0: 'Do Not Download',
1: 'Normal Priority',
2: 'High Priority',
5: 'Highest Priority'
},
priority_icons: {
0: '/static/images/tango/process-stop.png',
1: '/template/static/icons/16/gtk-yes.png',
2: '/static/images/tango/queue-down.png',
5: '/static/images/tango/go-bottom.png'
},
initialize: function(element, options) {
this.parent(element, options)
var menu = new Widgets.PopupMenu()
$A([0,1,2,5]).each(function(index) {
menu.add({
type:'text',
action: index,
text: this.priority_texts[index],
icon: this.priority_icons[index]
})
}, this)
menu.addEvent('action', function(e) {
e = {
action: e.action,
torrentId: menu.row.torrentId
}
this.fireEvent('menuAction', e)
}.bind(this))
this.addEvent('row_menu', function(e) {
e.stop()
menu.row = e.row
menu.show(e)
})
},
clear: function() {
this.rows.empty()
this.body.empty()
this.render()
},
update_files: function(torrent) {
torrent.files.each(function(file) {
var p = torrent.file_priorities[file.index]
var priority = {text:this.priority_texts[p], icon:this.priority_icons[p]}
var percent = torrent.file_progress[file.index]*100.0;
row = {
id: torrent.id + '-' + file.index,
data: {
filename: file.path,
size: file.size,
progress: {percent: percent, text: percent.toFixed(2) + '%'},
priority: priority
},
fileIndex: file.index,
torrentId: torrent.id
}
if (this.has(row.id)) {
this.updateRow(row, true)
} else {
this.addRow(row, true)
}
}, this)
this.render()
}
});
Deluge.Widgets.FilesPage = new Class({
Extends: Widgets.TabPage,
options: {
url: '/template/render/html/tab_files.html'
},
initialize: function(el) {
this.parent('Files')
this.torrentId = -1
this.addEvent('loaded', this.loaded.bindWithEvent(this))
this.addEvent('resize', this.resized.bindWithEvent(this))
},
loaded: function(event) {
this.grid = new Deluge.Widgets.FilesGrid('files')
this.grid.addEvent('menuAction', this.menuAction.bindWithEvent(this))
if (this.beenResized) {
this.resized(this.beenResized)
delete this.beenResized
}
},
resized: function(e) {
if (!this.grid) {
this.beenResized = e;
return
}
this.element.getPadding()
this.grid.sets({
width: e.width - this.element.padding.x,
height: e.height - this.element.padding.y
})
},
menuAction: function(e) {
this.fireEvent('menuAction', e)
},
update: function(torrent) {
if (this.torrentId != torrent.id) {
this.torrentId = torrent.id
this.grid.rows.empty()
this.grid.body.empty()
}
this.grid.update_files(torrent)
}
})
Deluge.Widgets.PeersPage = new Class({
Extends: Widgets.TabPage,
options: {
url: '/template/render/html/tab_peers.html'
},
initialize: function(el) {
this.parent('Peers')
this.addEvent('resize', this.resized.bindWithEvent(this))
this.addEvent('loaded', this.loaded.bindWithEvent(this))
},
loaded: function(event) {
this.grid = new Widgets.DataGrid($('peers'), {
columns: [
{name: 'country',type:'image',width: 20},
{name: 'address',text: 'Address',type:'text',width: 80},
{name: 'client',text: 'Client',type:'text',width: 180},
{name: 'downspeed',text: 'Down Speed',type:'speed',width: 100},
{name: 'upspeed',text: 'Up Speed',type:'speed',width: 100},
]})
this.torrentId = -1
if (this.been_resized) {
this.resized(this.been_resized)
delete this.been_resized
}
},
resized: function(e) {
if (!this.grid) {
this.been_resized = e;
return
}
this.element.getPadding()
this.grid.sets({
width: e.width - this.element.padding.x,
height: e.height - this.element.padding.y
})
},
update: function(torrent) {
if (this.torrentId != torrent.id) {
this.torrentId = torrent.id
this.grid.rows.empty()
this.grid.body.empty()
}
var peers = []
torrent.peers.each(function(peer) {
if (peer.country.strip() != '') {
peer.country = '/pixmaps/flags/' + peer.country.toLowerCase() + '.png'
} else {
peer.country = '/templates/static/images/spacer.gif'
}
row = {
id: peer.ip,
data: {
country: peer.country,
address: peer.ip,
client: peer.client,
downspeed: peer.down_speed,
upspeed: peer.up_speed
}
}
if (this.grid.has(row.id)) {
this.grid.updateRow(row, true)
} else {
this.grid.addRow(row, true)
}
peers.include(peer.ip)
}, this)
this.grid.rows.each(function(row) {
if (!peers.contains(row.id)) {
row.element.destroy()
this.grid.rows.erase(row)
}
}, this)
this.grid.render()
}
});
Deluge.Widgets.OptionsPage = new Class({
Extends: Widgets.TabPage,
options: {
url: '/template/render/html/tab_options.html'
},
initialize: function() {
if (!this.element)
this.parent('Options');
this.addEvent('loaded', function(event) {
this.loaded(event)
}.bindWithEvent(this))
},
loaded: function(event) {
this.bound = {
apply: this.apply.bindWithEvent(this),
reset: this.reset.bindWithEvent(this)
}
this.form = this.element.getElement('form');
this.changed = new Hash()
this.form.getElements('input').each(function(el) {
if (el.type == 'button') return;
el.focused = false
el.addEvent('change', function(e) {
if (!this.changed[this.torrentId])
this.changed[this.torrentId] = {}
if (el.type == 'checkbox')
this.changed[this.torrentId][el.name] = el.checked;
else
this.changed[this.torrentId][el.name] = el.value;
}.bindWithEvent(this));
el.addEvent('focus', function(e) {
el.focused = true;
});
el.addEvent('blur', function(e) {
el.focused = false;
});
}, this);
this.form.apply.addEvent('click', this.bound.apply);
this.form.reset.addEvent('click', this.bound.reset);
},
apply: function(event) {
if (!this.torrentId) return
var changed = this.changed[this.torrentId]
if ($defined(changed['is_auto_managed'])) {
changed['auto_managed'] = changed['is_auto_managed']
delete changed['is_auto_managed']
}
Deluge.Client.set_torrent_options(this.torrentId, changed, {
onSuccess: function(event) {
delete this.changed[this.torrentId]
}.bindWithEvent(this)
})
},
reset: function(event) {
if (this.torrentId) {
delete this.changed[this.torrentId]
}
Deluge.Client.get_torrent_status(this.torrentId, Deluge.Keys.Options, {
onSuccess: function(torrent) {
torrent.id = this.torrentId
this.update(torrent)
}.bindWithEvent(this)
})
},
update: function(torrent) {
this.torrentId = torrent.id;
$each(torrent, function(value, key) {
var changed = this.changed[this.torrentId]
if (changed && $defined(changed[key])) return;
var type = $type(value);
if (type == 'boolean') {
this.form[key].checked = value;
} else {
if (!this.form[key].focused)
this.form[key].value = value;
};
if (key == 'private' && value == 0) {
this.form[key].disabled = true
this.form[key].getParent().addClass('opt-disabled')
}
}, this);
}
});

View File

@ -0,0 +1,110 @@
Deluge.Menus = {
Torrents: [
{
type:'text',
action:'pause',
text: Deluge.Strings.get('Pause'),
icon:'/static/images/tango/pause.png'
},
{
type: 'text',
action: 'resume',
text: Deluge.Strings.get('Resume'),
icon: '/static/images/tango/start.png'
},
{ type: 'seperator' },
{
type:'submenu',
text: Deluge.Strings.get('Options'),
icon:'/static/images/tango/preferences-system.png',
items: [
{
type:'submenu',
text:'D/L Speed Limit',
icon:'/pixmaps/downloading16.png',
items: [
{
type:'text',
action:'max_download_speed',
value:5,
text:'5 KiB/s'
},
{
type:'text',
action:'max_download_speed',
value:10,
text:'10 KiB/s'
},
{
type:'text',
action:'max_download_speed',
value:30,
text:'30 KiB/s'
},
{
type:'text',
action:'max_download_speed',
value:80,
text:'80 KiB/s'
},
{
type:'text',
action:'max_download_speed',
value:300,
text:'300 KiB/s'
},
{
type:'text',
action:'max_download_speed',
value:-1,
text:'Unlimited'
}
]},
{type:'submenu',text:'U/L Speed Limit',icon:'/pixmaps/seeding16.png',items: [
{type:'text',action:'max_upload_speed',value:5,text:'5 KiB/s'},
{type:'text',action:'max_upload_speed',value:10,text:'10 KiB/s'},
{type:'text',action:'max_upload_speed',value:30,text:'30 KiB/s'},
{type:'text',action:'max_upload_speed',value:80,text:'80 KiB/s'},
{type:'text',action:'max_upload_speed',value:300,text:'300 KiB/s'},
{type:'text',action:'max_upload_speed',value:-1,text:'Unlimited'}
]},
{type:'submenu',text:'Connection Limit',icon:'/static/images/tango/connections.png',items: [
{type:'text',action:'max_connections',value:50,text:'50'},
{type:'text',action:'max_connections',value:100,text:'100'},
{type:'text',action:'max_connections',value:200,text:'200'},
{type:'text',action:'max_connections',value:300,text:'300'},
{type:'text',action:'max_connections',value:500,text:'500'},
{type:'text',action:'max_connections',value:-1,text:'Unlimited'}
]},
{type:'submenu',text:'Upload Slot Limit',icon:'/template/static/icons/16/view-sort-ascending.png',items: [
{type:'text',action:'max_upload_slots',value:0,text:'0'},
{type:'text',action:'max_upload_slots',value:1,text:'1'},
{type:'text',action:'max_upload_slots',value:2,text:'2'},
{type:'text',action:'max_upload_slots',value:3,text:'3'},
{type:'text',action:'max_upload_slots',value:5,text:'5'},
{type:'text',action:'max_upload_slots',value:-1,text:'Unlimited'}
]},
{type:'toggle',action:'auto_managed',value:false,text:'Auto Managed'}
]},
{type:'seperator'},
{type:'submenu',text:'Queue',icon:'/template/static/icons/16/view-sort-descending.png',items:[
{type:'text',action:'top',text:'Top',icon:'/static/images/tango/go-top.png'},
{type:'text',action:'up',text:'Up',icon:'/static/images/tango/queue-up.png'},
{type:'text',action:'down',text:'Down',icon:'/static/images/tango/queue-down.png'},
{type:'text',action:'bottom',text:'Bottom',icon:'/static/images/tango/go-bottom.png'}
]},
{type: 'seperator'},
{type:'text',action:'update_tracker',text:'Update Tracker',icon:'/template/static/icons/16/view-refresh.png'},
{type:'text',action:'edit_trackers',text:'Edit Trackers',icon:'/template/static/icons/16/gtk-edit.png'},
{type:'seperator'},
{type:'submenu',action:'remove',value:0,text:'Remove Torrent',icon:'/static/images/tango/list-remove.png', items:[
{type:'text',action:'remove',value:0,text:'From Session'},
{type:'text',action:'remove',value:1,text:'... and delete Torrent file'},
{type:'text',action:'remove',value:2,text:'... and delete Downloaded files'},
{type:'text',action:'remove',value:3,text:'... and delete All files'}
]},
{type:'seperator'},
{type:'text',action:'force_recheck',text:'Force Recheck',icon:'/static/images/tango/edit-redo.png'},
{type:'text',action:'move_storage',text:'Move Storage',icon:'/static/images/tango/move.png'}
]
}

View File

@ -0,0 +1,283 @@
/*
* Script: deluge-preferences.js
* Contains the classes that provides the preferences window with
* functionality
*
* Copyright:
* Damien Churchill (c) 2008
*/
Deluge.Widgets.PreferencesCategory = new Class({
Extends: Widgets.TabPage,
});
Deluge.Widgets.PluginPreferencesCategory = new Class({
Extends: Deluge.Widgets.PreferencesCategory
});
Deluge.Widgets.GenericPreferences = new Class({
Extends: Deluge.Widgets.PreferencesCategory,
initialize: function(name, options) {
this.parent(name, options)
this.core = true;
this.addEvent('loaded', function(e) {
this.form = this.element.getElement('form');
}.bindWithEvent(this));
},
update: function(config) {
this.fireEvent('beforeUpdate');
this.original = config;
this.changed = new Hash();
this.inputs = this.form.getElements('input, select');
this.inputs.each(function(input) {
if (!input.name) return;
if (!$defined(config[input.name])) return;
if (input.tagName.toLowerCase() == 'select') {
var value = config[input.name].toString();
input.getElements('option').each(function(option) {
if (option.value == value) {
option.selected = true;
}
});
} else if (input.type == 'text') {
input.value = config[input.name];
} else if (input.type == 'checkbox') {
input.checked = config[input.name];
} else if (input.type == 'radio') {
var value = config[input.name].toString()
if (input.value == value) {
input.checked = true;
}
}
input.addEvent('change', function(el) {
if (input.type == 'checkbox') {
if (this.original[input.name] == input.checked) {
if (this.changed[input.name])
delete this.changed[input.name];
} else {
this.changed[input.name] = input.checked
}
} else {
if (this.original[input.name] == input.value) {
if (this.changed[input.name])
delete this.changed[input.name];
} else {
this.changed[input.name] = input.value;
}
}
}.bindWithEvent(this))
}, this);
this.fireEvent('update');
},
getConfig: function() {
changed = {}
this.changed.each(function(value, key) {
var type = $type(this.original[key]);
if (type == 'number') {
changed[key] = Number(value);
} else if (type == 'string') {
changed[key] = String(value);
} else if (type == 'boolean') {
changed[key] = Boolean(value);
}
}, this);
return changed;
}
});
Deluge.Widgets.WebUIPreferences = new Class({
Extends: Deluge.Widgets.GenericPreferences,
options: {
url: '/template/render/html/preferences_webui.html'
},
initialize: function() {
this.parent('Web UI');
this.core = false;
this.addEvent('beforeUpdate', this.beforeUpdate.bindWithEvent(this));
this.addEvent('update', this.updated.bindWithEvent(this));
},
beforeUpdate: function(event) {
var templates = Deluge.Client.get_webui_templates({async: false});
this.form.template.empty();
templates.each(function(template) {
var option = new Element('option');
option.set('text', template);
this.form.template.grab(option);
}, this);
},
updated: function(event) {
if (this.form.template.value != 'ajax')
this.form.theme.disabled = true;
else
this.form.theme.disabled = false;
var theme = this.form.theme.getElement('option[value="' + Cookie.read('theme') + '"]')
theme.selected = true
this.form.template.addEvent('change', function(e) {
if (this.form.template.value != 'ajax') {
this.form.theme.disabled = true;
this.form.theme.addClass('disabled')
this.form.getElementById('lbl_theme').addClass('disabled')
} else {
this.form.theme.disabled = false;
this.form.getElementById('lbl_theme').removeClass('disabled')
this.form.theme.removeClass('disabled')
}
}.bindWithEvent(this));
},
apply: function() {
Deluge.UI.setTheme(this.form.theme.value);
Deluge.Client.set_webui_config(this.changed, {
onSuccess: function(e) {
if (this.changed['template']) location.reload(true);
}.bindWithEvent(this)
});
}
});
Deluge.Widgets.PreferencesWindow = new Class({
Extends: Widgets.Window,
options: {
width: 500,
height: 430,
title: 'Preferences',
url: '/template/render/html/window_preferences.html'
},
initialize: function() {
this.parent();
this.categories = [];
this.currentPage = -1;
this.addEvent('loaded', this.loaded.bindWithEvent(this));
this.addEvent('beforeShow', this.beforeShown.bindWithEvent(this));
},
loaded: function(event) {
this.catlist = this.content.getElement('.categories ul');
this.pages = this.content.getElement('.pref_pages');
this.title = this.pages.getElement('h3');
this.reset = this.content.getElement('.buttons .reset');
this.apply = this.content.getElement('.buttons .apply');
this.apply.addEvent('click', this.applied.bindWithEvent(this));
this.webui = new Deluge.Widgets.WebUIPreferences();
this.download = new Deluge.Widgets.GenericPreferences('Download', {
url: '/template/render/html/preferences_download.html'
});
this.network = new Deluge.Widgets.GenericPreferences('Network', {
url: '/template/render/html/preferences_network.html'
});
this.bandwidth = new Deluge.Widgets.GenericPreferences('Bandwidth', {
url: '/template/render/html/preferences_bandwidth.html'
});
this.daemon = new Deluge.Widgets.GenericPreferences('Daemon', {
url: '/template/render/html/preferences_daemon.html'
});
this.queue = new Deluge.Widgets.GenericPreferences('Queue', {
url: '/template/render/html/preferences_queue.html'
});
this.addCategory(this.webui);
this.addCategory(this.download);
this.addCategory(this.network);
this.addCategory(this.bandwidth);
this.addCategory(this.daemon);
this.addCategory(this.queue);
},
addCategory: function(category) {
this.categories.include(category);
var categoryIndex = this.categories.indexOf(category);
var tab = new Element('li');
tab.set('text', category.name);
tab.addEvent('click', function(e) {
this.select(categoryIndex);
}.bindWithEvent(this));
category.tab = tab;
this.catlist.grab(tab);
this.pages.grab(category.addClass('deluge-prefs-page'));
if (this.currentPage < 0) {
this.currentPage = categoryIndex;
this.select(categoryIndex);
};
},
select: function(id) {
this.categories[this.currentPage].removeClass('deluge-prefs-page-active');
this.categories[this.currentPage].tab.removeClass('deluge-prefs-active');
this.categories[id].addClass('deluge-prefs-page-active');
this.categories[id].tab.addClass('deluge-prefs-active');
this.title.set('text', this.categories[id].name);
this.currentPage = id;
this.fireEvent('pageChanged');
},
applied: function(event) {
var config = {};
this.categories.each(function(category) {
config = $merge(config, category.getConfig());
});
if ($defined(config['end_listen_port']) || $defined(config['start_listen_port'])) {
var startport = $pick(config['start_listen_port'], this.config['listen_ports'][0]);
var endport = $pick(config['end_listen_port'], this.config['listen_ports'][1]);
delete config['end_listen_port'];
delete config['start_listen_port'];
config['listen_ports'] = [startport, endport];
}
if ($defined(config['end_outgoing_port']) || $defined(config['start_outgoing_port'])) {
var startport = $pick(config['start_outgoing_port'], this.config['outgoing_ports'][0]);
var endport = $pick(config['end_outgoing_port'], this.config['outgoing_ports'][1]);
delete config['end_outgoing_port'];
delete config['start_outgoing_port'];
config['outgoing_ports'] = [startport, endport];
}
Deluge.Client.set_config(config, {
onSuccess: function(e) {
this.hide();
}.bindWithEvent(this)
});
this.webui.apply();
},
beforeShown: function(event) {
// we want this to be blocking
this.config = Deluge.Client.get_config({async: false});
// Unfortunately we have to modify the listen ports preferences
// in order to not have to modify the generic preferences class.
this.config['start_listen_port'] = this.config['listen_ports'][0];
this.config['end_listen_port'] = this.config['listen_ports'][1];
this.config['start_outgoing_port'] = this.config['outgoing_ports'][0];
this.config['end_outgoing_port'] = this.config['outgoing_ports'][1];
// Iterate through the pages and set the fields
this.categories.each(function(category) {
if (category.update && category.core) category.update(this.config);
}, this);
// Update the config for the webui pages.
var webconfig = Deluge.Client.get_webui_config({async: false});
this.webui.update(webconfig);
}
});

View File

@ -0,0 +1,92 @@
/*
* Script: deluge-torrent-grid.js
* The class for controlling the main torrent grid.
*
* Copyright:
* Damien Churchill (c) 2008
*/
Deluge.Widgets.TorrentGrid = new Class({
Extends: Widgets.DataGrid,
options: {
columns: [
{name: 'number',text: '#',type:'number',width: 20},
{name: 'name',text: 'Name',type:'icon',width: 350},
{name: 'size',text: 'Size',type:'bytes',width: 80},
{name: 'progress',text: 'Progress',type:'progress',width: 180},
{name: 'seeders',text: 'Seeders',type:'text',width: 80},
{name: 'peers',text: 'Peers',type:'text',width: 80},
{name: 'down',text: 'Down Speed',type:'speed',width: 100},
{name: 'up',text: 'Up Speed',type:'speed',width: 100},
{name: 'eta',text: 'ETA',type:'time',width: 80},
{name: 'ratio',text: 'Ratio',type:'number',width: 60},
{name: 'avail',text: 'Avail.',type:'number',width: 60}
]
},
icons: {
'Downloading': '/pixmaps/downloading16.png',
'Seeding': '/pixmaps/seeding16.png',
'Queued': '/pixmaps/queued16.png',
'Paused': '/pixmaps/inactive16.png',
'Error': '/pixmaps/alert16.png',
'Checking': '/pixmaps/inactive16.png'
},
get_selected_torrents: function() {
var torrentIds = [];
this.get_selected().each(function(row) {
torrentIds.include(row.id);
});
return torrentIds;
},
set_torrent_filter: function(state) {
state = state.replace(' ', '');
this.filterer = function (r) {
if (r.torrent.state == state) { return true } else { return false };
};
this.render();
},
update_torrents: function(torrents) {
torrents.getKeys().each(function(torrentId) {
var torrent = torrents[torrentId]
var torrentIds = torrents.getKeys()
if (torrent.queue == -1) {var queue = ''}
else {var queue = torrent.queue + 1}
var icon = this.icons[torrent.state]
row = {
id: torrentId,
data: {
number: queue,
name: {text: torrent.name, icon: icon},
size: torrent.total_size,
progress: {percent: torrent.progress, text:torrent.state + ' ' + torrent.progress.toFixed(2) + '%'},
seeders: torrent.num_seeds + ' (' + torrent.total_seeds + ')',
peers: torrent.num_peers + ' (' + torrent.total_peers + ')',
down: torrent.download_payload_rate,
up: torrent.upload_payload_rate,
eta: torrent.eta,
ratio: torrent.ratio.toFixed(3),
avail: torrent.distributed_copies.toFixed(3)
},
torrent: torrent
}
if (this.has(row.id)) {
this.updateRow(row, true)
} else {
this.addRow(row, true)
}
this.rows.each(function(row) {
if (!torrentIds.contains(row.id)) {
row.element.destroy()
this.rows.erase(row.id)
}
}, this)
}, this)
this.render()
}
});

View File

@ -0,0 +1,275 @@
/*
* Script: deluge-ui.js
* The main UI script.
*
* Copyright:
* Damien Churchill (c) 2008
*/
Deluge.UI = {
initialize: function() {
this.torrents = {};
this.torrentIds = [];
Deluge.Client = new JSON.RPC('/json/rpc');
var theme = Cookie.read('theme');
if (theme) this.setTheme(theme);
else this.setTheme('classic');
this.bound = {
updated: this.updated.bindWithEvent(this),
resized: this.resized.bindWithEvent(this),
toolbarClick: this.toolbarClick.bindWithEvent(this),
filePriorities: this.filePriorities.bindWithEvent(this),
labelsChanged: this.labelsChanged.bindWithEvent(this)
};
this.loadUi.delay(100, this);
},
loadUi: function() {
this.vbox = new Widgets.VBox('page', {expand: true});
this.toolbar = new Deluge.Widgets.Toolbar();
this.addWindow = new Deluge.Widgets.AddWindow();
this.prefsWindow = new Deluge.Widgets.PreferencesWindow();
this.statusbar = new Deluge.Widgets.StatusBar();
this.labels = new Deluge.Widgets.Labels()
this.details = new Deluge.Widgets.Details()
this.initialize_grid()
this.split_horz = new Widgets.SplitPane('top', this.labels, this.grid, {
pane1: {min: 150},
pane2: {min: 100, expand: true}
});
var details = $W('details')
this.split_vert = new Widgets.SplitPane('main', this.split_horz, details, {
direction: 'vertical',
pane1: {min: 100, expand: true},
pane2: {min: 200}
});
this.vbox.addBox(this.toolbar, {fixed: true});
this.vbox.addBox(this.split_vert);
this.vbox.addBox(this.statusbar, {fixed: true});
this.vbox.calculatePositions();
this.details.expand()
this.toolbar.addEvent('buttonClick', this.bound.toolbarClick);
this.details.addEvent('filesAction', this.bound.filePriorities)
this.labels.addEvent('stateChanged', this.bound.labelsChanged)
details.addEvent('resize', function(e) {
this.details.expand()
}.bindWithEvent(this))
window.addEvent('resize', this.bound.resized);
Deluge.UI.update();
this.overlay = $('overlay').dispose();
},
initialize_grid: function() {
this.grid = new Deluge.Widgets.TorrentGrid('torrents')
var menu = new Widgets.PopupMenu()
menu.add(Deluge.Menus.Torrents);
menu.addEvent('action', function(e) {
this.torrent_action(e.action, e.value)
}.bind(this))
this.grid.addEvent('row_menu', function(e) {
e.stop()
var value = this.grid.selectedRow.torrent.is_auto_managed;
menu.items[3].items[4].set(value)
menu.torrent_id = e.row_id
menu.show(e)
}.bindWithEvent(this))
this.grid.addEvent('selectedchanged', function(e) {
if ($chk(this.grid.selectedRow))
this.details.update(this.grid.selectedRow.id);
else
this.details.update(null);
}.bindWithEvent(this))
},
setTheme: function(name, fn) {
if (this.overlay) {
this.overlay.inject(document.body);
}
this.theme = name;
if (this.themecss) this.themecss.destroy();
this.themecss = new Asset.css('/template/static/themes/' + name + '/style.css');
Cookie.write('theme', name);
if (this.overlay) {
var refresh = function() {
this.vbox.refresh();
this.vbox.calculatePositions();
this.overlay.dispose();
}.bind(this);
var check = function() {
if (document.styleSheets[2]) {
if (document.styleSheets[2].href == this.themecss.href) {
refresh();
$clear(check);
}
}
}.periodical(50, this);
};
},
run: function() {
if (!this.running) {
this.running = this.update.periodical(2000, this);
}
},
stop: function() {
if (this.running) {
$clear(this.running);
this.running = false;
}
},
update: function() {
filter = {}
if (this.labels.state != 'All') filter.state = this.labels.state
Deluge.Client.update_ui(Deluge.Keys.Grid, filter, {
onSuccess: this.bound.updated
})
},
updated: function(data) {
this.torrents = new Hash(data.torrents);
this.stats = data.stats;
this.filters = data.filters
this.torrents.each(function(torrent, torrent_id) {
torrent.id = torrent_id;
})
this.grid.update_torrents(this.torrents);
this.statusbar.update(this.stats);
if ($chk(this.grid.selectedRow))
this.details.update(this.grid.selectedRow.id);
else
this.details.update(null);
this.labels.update(this.filters)
},
filePriorities: function(event) {
Deluge.Client.get_torrent_status(event.torrentId, ['file_priorities'], {
onSuccess: function(result) {
var priorities = result.file_priorities
priorities.each(function(priority, index) {
if (event.files.contains(index)) {
priorities[index] = event.action;
}
})
Deluge.Client.set_torrent_file_priorities(event.torrentId, priorities, {
onSuccess: function(response) {
this.details.update(event.torrentId)
}.bindWithEvent(this)
})
}.bindWithEvent(this)
})
},
resized: function(event) {
this.vbox.calculatePositions();
},
toolbarClick: function(event) {
this.torrent_action(event.action);
},
labelsChanged: function(event) {
this.update()
},
torrent_action: function(action, value) {
var torrentIds = this.grid.get_selected_torrents();
var client = Deluge.Client;
switch (action) {
case 'resume':
client.resume_torrent(torrentIds);
break;
case 'pause':
client.pause_torrent(torrentIds);
break;
case 'top':
client.queue_top(torrentIds);
break;
case 'up':
client.queue_up(torrentIds);
break;
case 'down':
client.queue_down(torrentIds);
break;
case 'bottom':
client.queue_bottom(torrentIds);
break;
case 'force_recheck':
client.force_recheck(torrentIds);
break;
case 'update_tracker':
client.force_reannounce(torrentIds);
break;
case 'max_download_speed':
value = value.toInt();
torrentIds.each(function(torrentId) {
client.set_torrent_max_download_speed(torrentId, value);
});
break;
case 'max_upload_speed':
value = value.toInt();
torrentIds.each(function(torrentId) {
client.set_torrent_max_upload_speed(torrentId, value);
});
break;
case 'max_connections':
value = value.toInt();
torrentIds.each(function(torrentId) {
client.set_torrent_max_connections(torrentId, value);
});
break;
case 'max_upload_slots':
value = value.toInt();
torrentIds.each(function(torrentId) {
client.set_torrent_max_upload_slots(torrentId, value);
});
break;
case 'auto_managed':
torrentIds.each(function(torrentId) {
client.set_torrent_auto_managed(torrentId, value);
});
break;
case 'add':
this.addWindow.show();
break;
case 'remove':
var removeTorrent = false, removeFiles = false;
if (value == 1) removeTorrent = true;
else if (value == 2) removeFiles = true;
else if (value > 3) {
removeTorrent = true;
removeFiles = true;
}
client.remove_torrent(torrentIds, removeTorrent, removeFiles);
break;
case 'preferences':
this.prefsWindow.show();
break;
default:
break;
}
this.update();
}
};
window.addEvent('domready', function(e) {
Deluge.UI.initialize();
Deluge.UI.run();
});

File diff suppressed because it is too large Load Diff

View File

@ -128,7 +128,7 @@ Array.implement({
Element.implement({
getInnerSize: function() {
this.getPadding()
if ((/^(?:body|html)$/i).test(this.tagName)) return this.getWindow().getSize();
if ((/^(?:body|html)$/i).test(this.tagName)) return window.getSize();
return {x: this.clientWidth - this.padding.x, y: this.clientHeight - this.padding.y};
},
@ -1479,4 +1479,4 @@ Widgets.DataGrid = new Class({
this.getById(row.id).update(row)
if (!noRender) this.render()
}
})
})