Compare commits

...

51 Commits

Author SHA1 Message Date
Damien Churchill
6892834d4d web: minor IE compatibility change 2011-11-25 23:47:08 +00:00
Damien Churchill
609f54a704 css: move icons out to their own stylesheet 2011-11-24 17:45:42 +00:00
Damien Churchill
fa08f7de43 details: add the missing items to the details tab
The web interface was missing the Owner and Shared items
that have been added to the gtk ui. Add these to bring the web
interface up to scratch.
2011-11-24 17:20:44 +00:00
Damien Churchill
a91037843b details: complete the status tab
Fix the remaining data items so they display correctly and tweak
the spacing to make the view a little more pleasant on the eye
2011-11-24 17:11:08 +00:00
Damien Churchill
4a43d6a635 data: fix type for progress column 2011-11-24 17:09:10 +00:00
Damien Churchill
1837d833c2 web: few sidebar fixes 2011-11-21 23:05:02 +00:00
Damien Churchill
e3e20aa14f web: fix using wrong Resource class
The Tracker class was still using the Resource class from Twisted instead
of our own subclass that adds some fun stuff :-)
2011-11-21 22:59:58 +00:00
Damien Churchill
c865486f82 web: add more jokey headers 2011-11-04 01:06:56 +00:00
Damien Churchill
c06d4dfea5 web: add a fun header
Add a jokey powered by header for people who like to
look at that sort of thing :-)
2011-11-04 00:50:11 +00:00
Damien Churchill
c405425993 web: fix details tab taking a while to update
Somewhere the handler for the torrent grid selection change
got removed during the upgrade to ext-4, add it back so the
details tab updating becomes instant once more.
2011-11-04 00:44:56 +00:00
Damien Churchill
d10752fc1a web: add a better log method
Add a new method, deluge.log which outputs to the javascript
console, including a date and time which will help when debugging
speed issues
2011-11-04 00:44:17 +00:00
Damien Churchill
ab665384d4 web: implement a better status tab
This new StatusTab uses a custom component, StatusItem and a
bunch of the Ext layout stuff in order to render the info on
the StatusTab, instead of an arbitary html modification. We
gain dynamic layout and more generic way of modifying the tab
2011-11-02 23:42:53 +00:00
Damien Churchill
f5e6eabee4 web: fix the details status tab
Start porting over the status tab to the new extjs4 format
2011-10-31 20:40:14 +00:00
Damien Churchill
717e66b836 web: big update for ext4.0.7 compatibility
Lots of changes here:

 * Switched to using Ext.create over new Object()
 * Add torrent window is now half working
 * Begin the makings of DnD add torrent file
2011-10-29 04:35:33 +01:00
Damien Churchill
fea0b41425 web: update extjs to 4.0.7 2011-10-29 01:28:58 +01:00
Damien Churchill
d37c3e0213 web: fix country flags
The flags have been moved into the ui folder so
the web server was looking in the wrong place
2011-10-21 21:49:34 +01:00
Damien Churchill
b724f74700 web: drop JSLoader extension
Ext now includes an Ext.Loader class that can load scripts so this
extra extension to do so is surplurfluous.
2011-10-05 23:31:41 +01:00
Damien Churchill
d44a357284 web: fix the sidebar and filterpanels
The filters in the sidebar can now be switch between finally. It
was down to the setTitle method overwriting whatever the accordion
layout was adding in.
2011-10-05 02:31:51 +01:00
Damien Churchill
d6715fcbb9 web: fix the filterpanel column width
Set flex = 1 on the column so it auto expands to take up the
entire available width.
2011-10-05 02:21:06 +01:00
Damien Churchill
2853d028fd web: more progressbar fixes
Fix displaying the progress bars within the peers tab, also
reduce the modifier so that the bars don't overflow their
containers.
2011-10-05 02:05:58 +01:00
Damien Churchill
4ab5c6d9de web: fix selecting the active tab
Fix selecting the active tab in the details panel, it seems that
the activeTab property wasn't working so explicitly call
setActiveTab after adding in the various panels.
2011-10-05 01:54:33 +01:00
Damien Churchill
f53dc5faaf web: random fixes
Just a bunch of random fixes to improve the situation whilst
trying to convert over to extjs4.
2011-10-05 01:41:49 +01:00
Damien Churchill
c46bc049d1 web: add files resource to the web server
Add a files resource that allows Ext to fetch the file tree via
one of it's ajax proxies.
2011-10-05 01:40:40 +01:00
Damien Churchill
39d19b5afd web: ensure torrent keys are always str
Make sure that we aren't sending unicode strings as keys, always
map them with str.
2011-10-05 01:40:40 +01:00
Damien Churchill
e8506b925f web: fix the progressbar renderer
Modify our progress bar renderer so it uses the new ext style
and actually creates a progress bar now :-)
2011-10-05 01:40:40 +01:00
Damien Churchill
eb9071fcb0 web: add a secure decorator to the auth module
This new decorator will make it easy to secure the render method
of twisted resources as we will be adding a fair few as more of
the interface moves to use ajax requests over json-rpc.
2011-10-05 01:38:37 +01:00
Damien Churchill
9362ec0103 ui: add a new file tree geared towards ext
Add a new file tree that is more suited to created a tree that
an ext proxy will be able to load and convert into a data store.
This file tree also has an improved file tree walk method that
uses generators instead of callbacks.
2011-10-05 01:38:37 +01:00
Damien Churchill
fe0332bccf web: allow the peers grid to be stateful
Give the peers grid an id so it can store it's state and be
guaranteed to be able to restore it upon a refresh.
2011-10-05 01:38:37 +01:00
Damien Churchill
64bacbfbf4 web: support using localStorage for state
This adds support for checking to see if the browser supports
the HTML5 localStorage, if so use that instead of cookies for
storing the UI state.
2011-10-05 01:38:37 +01:00
Damien Churchill
280377ad6f web: convert the peers tab to use an ext proxy
Instead of fetching the peer information via a rpc call simply
expose it as a fetching page via ajax so we can make use of
the Ext proxy and reader instead of manually loading it into
the store ourselves.
2011-10-05 01:38:37 +01:00
Damien Churchill
0c3d2322cc web: add loading mask
Add a loading mask that hides the loading of the interface with
some text and a nice ajax spinner. The situation can be further
improved by loading all of the scripts and other resources
dynamically, which will be added later.
2011-10-05 01:36:58 +01:00
Damien Churchill
07b6db0c98 web: update to extjs 4.0.2a 2011-10-05 01:36:58 +01:00
Damien Churchill
713953ec03 web: fix the toolbar actions
Use the proper method for getting the torrent ids instead of the
implementation within the toolbar. Using the one on the torrent
grid will be more likely to work.
2011-10-05 01:36:58 +01:00
Damien Churchill
6324737031 web: simple formatting change
Nicely space out a few dictionaries so they are easier on the
eye when reading the code.
2011-10-05 01:36:58 +01:00
Damien Churchill
428681aca3 webui: use the getId method in the details panel
Before we were using the id property which seems to have been
deprecated and wasn't returning the actual id. Switching to
use the getId() method returns the correct id (the torrent hash)
so grabbing the torrent details starts working again for the
details tabs.
2011-10-05 01:36:57 +01:00
Damien Churchill
317e9ee423 webui: fix the details tab
The path to DomHelper isn't working, so fix that, and also update
the copyright notices.
2011-10-05 01:36:57 +01:00
Damien Churchill
08e774bbda webui: fix displaying the torrent context menu
The event name and arguments has changed, as well as the response
from getPoint, nothing major.
2011-10-05 01:36:57 +01:00
Damien Churchill
43cb787b44 webui: fix closing the connection manager
Don't override the onHide method in the ConnectionManager, this
was stopping the window from being able to close.
2011-10-05 01:36:57 +01:00
Damien Churchill
fb8f1e7ebc web: fix the FilterPanel to a degree
This finishes converting the FilterPanel to use the new data stuff
from ExtJS4 as well as switching from a listview to a gridview.
Currently the Sidebar is still broken.
2011-10-05 01:36:57 +01:00
Damien Churchill
881bcee160 web: fix starting/stopping daemons
Just a simple change from listview to gridview here.
2011-10-05 01:36:57 +01:00
Damien Churchill
42b8af25aa milestone number 1, web interface loads now 2011-10-05 01:36:57 +01:00
Damien Churchill
bf4b826809 webui: fix the login window
The login window now functions correctly under ExtJS 4.0.
2011-10-05 01:36:57 +01:00
Damien Churchill
8ae14de208 webui: fix up the connection manager
Partially fix the connection manager so it now displays correctly
on first load. A lot of the functionality needs to be changed
due to the list -> grid migration.
2011-10-05 01:36:57 +01:00
Damien Churchill
5b45670a85 webui: first commit where the interface loads
At this point the interface loads, but it is misshapen and needs a lot more
work to get it fully extjs 4.0 compatible.
2011-10-05 01:36:57 +01:00
Damien Churchill
6cdf9940d3 add extjs javascript files too 2011-10-05 01:31:14 +01:00
Damien Churchill
8b69d66bae tidy up some deferred stuff 2011-10-05 01:31:13 +01:00
Damien Churchill
3ee434975c upgrade to extjs 4.0.2 2011-10-05 01:31:13 +01:00
Damien Churchill
dda4620d98 remove and update the ext-extensions 2011-10-05 01:31:13 +01:00
Damien Churchill
7ac0083239 remove more extensions that have been moved into core 2011-10-05 01:31:13 +01:00
Damien Churchill
6ae58248a1 remove the treegrid extensions as they are now included with extjs 2011-10-05 01:31:12 +01:00
Damien Churchill
1c78bcbb29 upgrade to extjs4 2011-10-05 01:31:12 +01:00
1511 changed files with 280390 additions and 84694 deletions

View File

@ -0,0 +1,46 @@
from twisted.trial import unittest
from deluge.ui.common import ExtFileTree
class ExtFileTreeTestCase(unittest.TestCase):
def test_simple_tree(self):
paths = [
"SomeRootFolder/file1",
"SomeRootFolder/file2",
"SomeRootFolder/subfolder1/subfile1",
"SomeRootFolder/subfolder1/subfile2"
]
tree = ExtFileTree(paths)
self.assertEqual(tree.tree, {"children": [
{"text": "SomeRootFolder", "children": [
{"text": "file1"},
{"text": "file2"},
{"text": "subfolder1", "children": [
{"text": "subfile1"},
{"text": "subfile2"}
]}
]}
], "text": ""})
def test_tree_walk(self):
paths = [
"SomeRootFolder/file1",
"SomeRootFolder/file2",
"SomeRootFolder/subfolder1/subfile1",
"SomeRootFolder/subfolder1/subfile2"
]
tree = ExtFileTree(paths)
for path, obj in tree.walk():
if path == "SomeRootFolder/file1":
obj["size"] = 1024
self.assertEqual(tree.tree, {"children": [
{"text": "SomeRootFolder", "children": [
{"text": "file1", "size": 1024},
{"text": "file2"},
{"text": "subfolder1", "children": [
{"text": "subfile1"},
{"text": "subfile2"}
]}
]}
], "text": ""})

View File

@ -244,6 +244,83 @@ class TorrentInfo(object):
""" """
return self.__m_filedata return self.__m_filedata
class ExtFileTree(object):
"""
Convert a list of paths into a compatible file tree format for Ext.
:param paths: The paths to be converted
:type paths: list
"""
def __init__(self, paths):
self.tree = {"children": [], "text": ""}
def get_parent(path):
parent = self.tree
while "/" in path:
directory, sep, path = path.partition("/")
new_parent = None
for child in parent["children"]:
if child["text"] == directory:
new_parent = child
if not new_parent:
new_parent = {"children": [], "text": directory}
parent["children"].append(new_parent)
parent = new_parent
return parent, path
for path in paths:
if path[-1] == "/":
path = path[:-1]
parent, path = get_parent(path)
parent["children"].append({
"text": path,
"children": []
})
else:
parent, path = get_parent(path)
parent["children"].append({"text": path})
def get_tree(self):
"""
Return the tree.
:returns: the file tree.
:rtype: dictionary
"""
return self.tree
def walk(self):
"""
Walk through the file tree calling the callback function on each item
contained.
:param callback: The function to be used as a callback, it should have
the signature func(item, path) where item is a `tuple` for a file
and `dict` for a directory.
:type callback: function
"""
for path, child in self.__walk(self.tree, ""):
yield path, child
def __walk(self, directory, parent_path):
for item in directory["children"]:
path = path_join(parent_path, item["text"])
if "children" in item:
for path, child in self.__walk(item, path):
yield path, child
yield path, item
def __str__(self):
lines = []
def write(path, item):
depth = path.count("/")
path = os.path.basename(path)
path = path + "/" if item["type"] == "dir" else path
lines.append(" " * depth + path)
self.walk(write)
return "\n".join(lines)
class FileTree2(object): class FileTree2(object):
""" """
Converts a list of paths in to a file tree. Converts a list of paths in to a file tree.

View File

@ -51,11 +51,14 @@ import time
import random import random
import hashlib import hashlib
import logging import logging
from datetime import datetime, timedelta from datetime import datetime, timedelta
from email.utils import formatdate from email.utils import formatdate
from types import FunctionType
from twisted.internet.defer import Deferred from twisted.internet.defer import Deferred
from twisted.internet.task import LoopingCall from twisted.internet.task import LoopingCall
from twisted.web.http import FORBIDDEN
from deluge import component from deluge import component
from deluge.ui.web.json_api import JSONComponent, export from deluge.ui.web.json_api import JSONComponent, export
@ -89,6 +92,29 @@ def make_expires(timeout):
expires_str = formatdate(timeval=expires, localtime=False, usegmt=True) expires_str = formatdate(timeval=expires, localtime=False, usegmt=True)
return expires, expires_str return expires, expires_str
def secure(auth_level=AUTH_LEVEL_DEFAULT):
"""
Decorator function to secure a Twisted resource ensuring that the
user is authenticated with the web interface.
"""
def wrap(func, *args, **kwargs):
def secure_render(self, request):
try:
component.get("Auth").check_request(request,
level=auth_level)
except AuthError:
request.setResponseCode(FORBIDDEN)
return "<h1>Forbidden</h1>"
return func(self, request)
return secure_render
if type(auth_level) is FunctionType:
func = auth_level
auth_level = AUTH_LEVEL_DEFAULT
return wrap(func)
else:
return wrap
class Auth(JSONComponent): class Auth(JSONComponent):
""" """
The component that implements authentification into the JSON interface. The component that implements authentification into the JSON interface.
@ -136,7 +162,7 @@ class Auth(JSONComponent):
checksum = str(make_checksum(session_id)) checksum = str(make_checksum(session_id))
request.addCookie('_session_id', session_id + checksum, request.addCookie('_session_id', session_id + checksum,
path=request.base+"json", expires=expires_str) path=request.base, expires=expires_str)
log.debug("Creating session for %s", login) log.debug("Creating session for %s", login)
config = component.get("DelugeWeb").config config = component.get("DelugeWeb").config
@ -233,7 +259,7 @@ class Auth(JSONComponent):
_session_id = request.getCookie("_session_id") _session_id = request.getCookie("_session_id")
request.addCookie('_session_id', _session_id, request.addCookie('_session_id', _session_id,
path=request.base+"json", expires=expires_str) path=request.base, expires=expires_str)
if method: if method:
if not hasattr(method, "_json_export"): if not hasattr(method, "_json_export"):

View File

@ -37,6 +37,8 @@ import zlib
import gettext import gettext
from deluge import common from deluge import common
from twisted.web.resource import Resource as _Resource
_ = lambda x: gettext.gettext(x).decode("utf-8") _ = lambda x: gettext.gettext(x).decode("utf-8")
def escape(text): def escape(text):
@ -86,3 +88,10 @@ except ImportError:
raise RuntimeError( raise RuntimeError(
"The Mako library is required to run deluge.ui.web" "The Mako library is required to run deluge.ui.web"
) )
class Resource(_Resource):
def render(self, request):
request.setHeader("x-powered-by", "Rum")
request.setHeader("x-accept-rum",
"Morgans Spiced, Sailor Jerry, Bundaberg")

View File

@ -11,13 +11,55 @@ input {
color: Black; color: Black;
} }
#loading-mask {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: 20000;
background-color: white;
}
#loading {
position: absolute;
left: 50%;
top: 50%;
padding: 2px;
z-index: 20001;
height: auto;
margin: -35px 0 0 -30px;
}
#loading .loading-indicator {
background: url('../images/loading.gif') no-repeat;
color: #555;
font: 24px "UbuntuBeta Regular",Ubuntu,"Bitstream Vera Sans","DejaVu Sans",Tahoma,sans-serif;
padding: 2px 42px;
margin: 0;
text-align: center;
height: auto;
}
.x-deluge-dropzone {
position: absolute;
z-index: 1;
margin: 10px;
border: 2px dashed black;
width: 420px;
height: 110px;
line-height: 110px;
text-align: center;
font-size: 2em;
}
.x-deluge-main-panel { .x-deluge-main-panel {
background-image: url('../icons/deluge.png'); background-image: url('../icons/deluge.png');
} }
.deluge-torrents td, .x-deluge-peers td { .deluge-torrents td, .x-deluge-peers td {
height: 16px; height: 16px;
line-height: 16px; line-height: 16px !important;
} }
.deluge-torrents .torrent-name, .x-deluge-peer, .x-deluge-seed { .deluge-torrents .torrent-name, .x-deluge-peer, .x-deluge-seed {
@ -49,6 +91,18 @@ input {
.x-deluge-install-plugin, .x-btn .x-deluge-install-plugin {background-image: url('../icons/install_plugin.png'); } .x-deluge-install-plugin, .x-btn .x-deluge-install-plugin {background-image: url('../icons/install_plugin.png'); }
.x-deluge-find-more, .x-btn .x-deluge-find-more {background-image: url('../icons/find_more.png'); } .x-deluge-find-more, .x-btn .x-deluge-find-more {background-image: url('../icons/find_more.png'); }
.x-status-item {
position: relative;
}
.x-status-label {
font-weight: bold;
display: inline-block;
}
.x-status-text {
display: inline-block;
}
/* Torrent Details */ /* Torrent Details */
#torrentDetails dl, dl.singleline { #torrentDetails dl, dl.singleline {
@ -81,41 +135,6 @@ dl.singleline dd {
background: White; background: White;
} }
/* Torrent Details - Status Tab */
.x-deluge-status-progressbar {
margin: 5px;
}
.x-deluge-status {
margin: 10px;
}
.x-deluge-status dd.downloaded,
.x-deluge-status dd.uploaded,
.x-deluge-status dd.share,
.x-deluge-status dd.announce,
.x-deluge-status dd.tracker_status {
width: 200px;
margin-left: 100px;
}
.x-deluge-status dd.downspeed,
.x-deluge-status dd.upspeed,
.x-deluge-status dd.eta,
.x-deluge-status dd.pieces {
margin-left: 100px;
}
.x-deluge-status dd.active_time,
.x-deluge-status dd.seeding_time,
.x-deluge-status dd.seed_rank,
.x-deluge-status dd.time_added {
width: 100px;
}
.x-deluge-status dd.last_seen_complete {
width: 100px;
}
/* Torrent Details - Details Tab */ /* Torrent Details - Details Tab */
#torrentDetails dd.torrent_name, #torrentDetails dd.torrent_name,
#torrentDetails dd.status, #torrentDetails dd.status,
@ -147,7 +166,7 @@ dl.singleline dd {
.x-deluge-add-torrent-name-loading { .x-deluge-add-torrent-name-loading {
padding-left: 20px; padding-left: 20px;
line-height: 20px; line-height: 20px;
background: url('/themes/default/tree/loading.gif') no-repeat 2px; background: url('/resources/themes/images/default/tree/loading.gif') no-repeat 2px;
} }
/* Add Url Window */ /* Add Url Window */
@ -290,130 +309,3 @@ dl.singleline dd {
.x-mixed-download { .x-mixed-download {
/*background-image: url(../icons/mixed.png);*/ /*background-image: url(../icons/mixed.png);*/
} }
/**
* Deluge Default Icon Set
* n.b. this needs to be forked out at some point
*/
.icon-create {
background-image: url('../icons/create.png') !important;
}
.icon-add {
background-image: url('../icons/add.png') !important;
}
.icon-add-url {
background-image: url('../icons/add_url.png') !important;
}
.icon-add-magnet {
background-image: url('../icons/add_magnet.png') !important;
}
.icon-pause {
background-image: url('../icons/pause.png') !important;
}
.icon-resume {
background-image: url('../icons/start.png') !important;
}
.icon-options {
background-image: url('../icons/preferences.png') !important;
}
.icon-queue {
background-image: url('../icons/queue.png') !important;
}
.icon-top {
background-image: url('../icons/top.png') !important;
}
.icon-up {
background-image: url('../icons/up.png') !important;
}
.icon-down {
background-image: url('../icons/down.png') !important;
}
.icon-bottom {
background-image: url('../icons/bottom.png') !important;
}
.icon-update-tracker {
background-image: url('../icons/update.png') !important;
}
.icon-edit-trackers, .icon-edit {
background-image: url('../icons/edit_trackers.png') !important;
}
.icon-remove {
background-image: url('../icons/remove.png') !important;
}
.icon-recheck {
background-image: url('../icons/recheck.png') !important;
}
.icon-move {
background-image: url('../icons/move.png') !important;
}
.icon-help {
background-image: url('../icons/help.png') !important;
}
.icon-logout {
background-image: url('../icons/logout.png') !important;
}
.icon-back {
background-image: url('../icons/back.png') !important;
}
.icon-forward {
background-image: url('../icons/forward.png') !important;
}
.icon-home {
background-image: url('../icons/home.png') !important;
}
.icon-ok {
background-image: url('../icons/ok.png') !important;
}
.icon-error {
background-image: url('../icons/error.png') !important;
}
.icon-upload-slots {
background-image: url('../icons/upload_slots.png') !important;
}
.icon-expand-all {
background-image: url('../icons/expand_all.png') !important;
}
.icon-do-not-download {
background-image: url('../icons/no_download.png') !important;
}
.icon-normal {
background-image: url('../icons/normal.png') !important;
}
.icon-high {
background-image: url('../icons/high.png') !important;
}
.icon-highest {
background-image: url('../icons/highest.png') !important;
}

File diff suppressed because it is too large Load Diff

111
deluge/ui/web/css/icons.css Normal file
View File

@ -0,0 +1,111 @@
.icon-create {
background-image: url('../icons/create.png') !important;
}
.icon-add {
background-image: url('../icons/add.png') !important;
}
.icon-add-url {
background-image: url('../icons/add_url.png') !important;
}
.icon-add-magnet {
background-image: url('../icons/add_magnet.png') !important;
}
.icon-options {
background-image: url('../icons/preferences.png') !important;
}
.icon-queue {
background-image: url('../icons/queue.png') !important;
}
.icon-top {
background-image: url('../icons/top.png') !important;
}
.icon-up {
background-image: url('../icons/up.png') !important;
}
.icon-down {
background-image: url('../icons/down.png') !important;
}
.icon-bottom {
background-image: url('../icons/bottom.png') !important;
}
.icon-update-tracker {
background-image: url('../icons/update.png') !important;
}
.icon-edit-trackers, .icon-edit {
background-image: url('../icons/edit_trackers.png') !important;
}
.icon-remove {
background-image: url('../icons/remove.png') !important;
}
.icon-recheck {
background-image: url('../icons/recheck.png') !important;
}
.icon-move {
background-image: url('../icons/move.png') !important;
}
.icon-help {
background-image: url('../icons/help.png') !important;
}
.icon-logout {
background-image: url('../icons/logout.png') !important;
}
.icon-back {
background-image: url('../icons/back.png') !important;
}
.icon-forward {
background-image: url('../icons/forward.png') !important;
}
.icon-home {
background-image: url('../icons/home.png') !important;
}
.icon-ok {
background-image: url('../icons/ok.png') !important;
}
.icon-error {
background-image: url('../icons/error.png') !important;
}
.icon-upload-slots {
background-image: url('../icons/upload_slots.png') !important;
}
.icon-expand-all {
background-image: url('../icons/expand_all.png') !important;
}
.icon-do-not-download {
background-image: url('../icons/no_download.png') !important;
}
.icon-normal {
background-image: url('../icons/normal.png') !important;
}
.icon-high {
background-image: url('../icons/high.png') !important;
}
.icon-highest {
background-image: url('../icons/highest.png') !important;
}

View File

@ -22,7 +22,7 @@ GetText = {
} }
} }
function _(string) { window._ = function(string) {
return GetText.get(string); return GetText.get(string);
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -19,7 +19,7 @@
author: 'Damien Churchill <damoxc@gmail.com>', author: 'Damien Churchill <damoxc@gmail.com>',
version: '${version}', version: '${version}',
config: ${js_config} config: ${js_config}
} };
</script> </script>
<!-- Javascript --> <!-- Javascript -->
@ -31,7 +31,12 @@
</script> </script>
</head> </head>
<body> <body>
<div style="background-image: url('${base}themes/images/default/tree/loading.gif');"></div> <div id="loading-mask"></div>
<div id="loading">
<div class="loading-indicator">
Loading...
</div>
</div>
<!-- Preload icon classes --> <!-- Preload icon classes -->
<div class="ext-mb-error"></div> <div class="ext-mb-error"></div>

View File

@ -1,2 +1,3 @@
+ OptionsManager.js + OptionsManager.js
+ StatusbarMenu.js + StatusbarMenu.js
+ Formatters.js

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.AddConnectionWindow.js * Deluge.AddConnectionWindow.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,13 +29,13 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.ns('Deluge');
/** /**
* @class Deluge.AddConnectionWindow * @class Deluge.AddConnectionWindow
* @extends Ext.Window * @extends Ext.Window
*/ */
Deluge.AddConnectionWindow = Ext.extend(Ext.Window, { Ext.define('Deluge.AddConnectionWindow', {
extend: 'Ext.Window',
title: _('Add Connection'), title: _('Add Connection'),
iconCls: 'x-deluge-add-window-icon', iconCls: 'x-deluge-add-window-icon',
@ -48,14 +48,26 @@ Deluge.AddConnectionWindow = Ext.extend(Ext.Window, {
closeAction: 'hide', closeAction: 'hide',
initComponent: function() { initComponent: function() {
Deluge.AddConnectionWindow.superclass.initComponent.call(this); this.callParent(arguments);
this.addEvents('hostadded'); this.addEvents('hostadded');
this.addButton(_('Close'), this.hide, this); this.addDocked({
this.addButton(_('Add'), this.onAddClick, this); xtype: 'toolbar',
dock: 'bottom',
defaultType: 'button',
items: [
'->',
{text: _('Close'), handler: function() {
this.setVisible(false);
}, scope: this},
{text: _('Add'), handler: this.onAddClick, scope: this}
]
});
this.on('hide', this.onHide, this); this.on('hide', function() {
this.form.getForm().reset();
}, this);
this.form = this.add({ this.form = this.add({
xtype: 'form', xtype: 'form',
@ -65,28 +77,22 @@ Deluge.AddConnectionWindow = Ext.extend(Ext.Window, {
items: [{ items: [{
fieldLabel: _('Host'), fieldLabel: _('Host'),
name: 'host', name: 'host',
anchor: '75%',
value: '' value: ''
}, { }, {
xtype: 'spinnerfield', xtype: 'numberfield',
fieldLabel: _('Port'), fieldLabel: _('Port'),
name: 'port', name: 'port',
strategy: { width: 175,
xtype: 'number', value: 58846,
decimalPrecision: 0,
minValue: -1, minValue: -1,
maxValue: 65535 maxValue: 65535,
}, decimalPrecision: 0,
value: '58846',
anchor: '40%'
}, { }, {
fieldLabel: _('Username'), fieldLabel: _('Username'),
name: 'username', name: 'username',
anchor: '75%',
value: '' value: ''
}, { }, {
fieldLabel: _('Password'), fieldLabel: _('Password'),
anchor: '75%',
name: 'password', name: 'password',
inputType: 'password', inputType: 'password',
value: '' value: ''
@ -114,9 +120,5 @@ Deluge.AddConnectionWindow = Ext.extend(Ext.Window, {
}, },
scope: this scope: this
}); });
},
onHide: function() {
this.form.getForm().reset();
} }
}); });

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.AddTrackerWindow.js * Deluge.AddTrackerWindow.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,13 +29,13 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.ns('Deluge');
/** /**
* @class Deluge.AddTrackerWindow * @class Deluge.AddTrackerWindow
* @extends Ext.Window * @extends Ext.Window
*/ */
Deluge.AddTrackerWindow = Ext.extend(Ext.Window, { Ext.define('Deluge.AddTrackerWindow', {
extend: 'Ext.Window',
title: _('Add Tracker'), title: _('Add Tracker'),
layout: 'fit', layout: 'fit',
@ -51,10 +51,10 @@ Deluge.AddTrackerWindow = Ext.extend(Ext.Window, {
iconCls: 'x-deluge-edit-trackers', iconCls: 'x-deluge-edit-trackers',
initComponent: function() { initComponent: function() {
Deluge.AddTrackerWindow.superclass.initComponent.call(this); this.callParent(arguments);
this.addButton(_('Cancel'), this.onCancelClick, this); //this.addButton(_('Cancel'), this.onCancelClick, this);
this.addButton(_('Add'), this.onAddClick, this); //this.addButton(_('Add'), this.onAddClick, this);
this.addEvents('add'); this.addEvents('add');
this.form = this.add({ this.form = this.add({

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.Client.js * Deluge.Client.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,7 +29,6 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.namespace('Ext.ux.util');
/** /**
* A class that connects to a json-rpc resource and adds the available * A class that connects to a json-rpc resource and adds the available
@ -37,7 +36,8 @@ Ext.namespace('Ext.ux.util');
* @class Ext.ux.util.RpcClient * @class Ext.ux.util.RpcClient
* @namespace Ext.ux.util * @namespace Ext.ux.util
*/ */
Ext.ux.util.RpcClient = Ext.extend(Ext.util.Observable, { Ext.define('Ext.ux.util.RpcClient', {
extend: 'Ext.util.Observable',
_components: [], _components: [],
@ -159,7 +159,7 @@ Ext.ux.util.RpcClient = Ext.extend(Ext.util.Observable, {
}); });
if (isOption) { if (isOption) {
params.remove(options) params.pop(-1)
} else { } else {
options = {} options = {}
} }

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.ConnectionManager.js * Deluge.ConnectionManager.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -30,7 +30,8 @@
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Deluge.ConnectionManager = Ext.extend(Ext.Window, { Ext.define('Deluge.ConnectionManager', {
extend: 'Ext.Window',
layout: 'fit', layout: 'fit',
width: 300, width: 300,
@ -44,84 +45,69 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
iconCls: 'x-deluge-connect-window-icon', iconCls: 'x-deluge-connect-window-icon',
initComponent: function() { initComponent: function() {
Deluge.ConnectionManager.superclass.initComponent.call(this); this.callParent(arguments);
this.on('hide', this.onHide, this); this.afterMethod('onHide', this.afterHidden, this);
this.on('show', this.onShow, this); this.afterMethod('onShow', this.afterShown, this);
deluge.events.on('login', this.onLogin, this); deluge.events.on('login', this.onLogin, this);
deluge.events.on('logout', this.onLogout, this); deluge.events.on('logout', this.onLogout, this);
this.addButton(_('Close'), this.onClose, this); this.addDocked({
this.addButton(_('Connect'), this.onConnect, this); xtype: 'toolbar',
dock: 'bottom',
defaultType: 'button',
items: [
'->',
{text: _('Close'), handler: this.onClose, scope: this},
{text: _('Connect'), handler: this.onConnect, scope: this}
]
});
this.list = new Ext.list.ListView({ this.grid = this.add({
store: new Ext.data.ArrayStore({ xtype: 'grid',
fields: [ autoScroll: true,
{name: 'status', mapping: 3}, store: Ext.create('Ext.data.Store', {
{name: 'host', mapping: 1}, model: 'Deluge.data.Host',
{name: 'port', mapping: 2}, proxy: {
{name: 'version', mapping: 4} type: 'memory',
], reader: {
id: 0 type: 'json',
root: 'hosts',
idProperty: 'id'
}
}
}), }),
columns: [{ columns: [{
header: _('Status'), header: _('Status'),
width: .24, width: 70,
sortable: true, sortable: true,
dataIndex: 'status' dataIndex: 'status'
}, { }, {
id:'host', xtype: 'templatecolumn',
flex: 1,
header: _('Host'), header: _('Host'),
width: .51,
sortable: true, sortable: true,
tpl: '{host}:{port}', tpl: '{host}:{port}'
dataIndex: 'host'
}, { }, {
xtype: 'templatecolumn',
header: _('Version'), header: _('Version'),
width: .25, width: 70,
sortable: true, sortable: true,
tpl: '<tpl if="version">{version}</tpl>', tpl: '<tpl if="version">{version}</tpl>'
dataIndex: 'version'
}], }],
singleSelect: true, singleSelect: true,
listeners: { listeners: {
'selectionchange': {fn: this.onSelectionChanged, scope: this} 'selectionchange': {fn: this.onSelectionChanged, scope: this}
} },
bbar: [
{xtype: 'button', text: _('Add'), iconCls: 'icon-add', handler: this.onAddClick, scope: this},
{xtype: 'button', text: _('Remove'), iconCls: 'icon-remove', handler: this.onRemoveClick, scope: this},
'->',
{xtype: 'button', text: _('Stop Daemon'), iconCls: 'icon-error', handler: this.onStopClick, scope: this, disabled: true}
]
}); });
this.panel = this.add({ this.update = Ext.Function.bind(this.update, this);
autoScroll: true,
items: [this.list],
bbar: new Ext.Toolbar({
buttons: [
{
id: 'cm-add',
cls: 'x-btn-text-icon',
text: _('Add'),
iconCls: 'icon-add',
handler: this.onAddClick,
scope: this
}, {
id: 'cm-remove',
cls: 'x-btn-text-icon',
text: _('Remove'),
iconCls: 'icon-remove',
handler: this.onRemoveClick,
disabled: true,
scope: this
}, '->', {
id: 'cm-stop',
cls: 'x-btn-text-icon',
text: _('Stop Daemon'),
iconCls: 'icon-error',
handler: this.onStopClick,
disabled: true,
scope: this
}
]
})
});
this.update = this.update.createDelegate(this);
}, },
/** /**
@ -157,8 +143,8 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
}, },
update: function() { update: function() {
this.list.getStore().each(function(r) { this.grid.getStore().each(function(r) {
deluge.client.web.get_host_status(r.id, { deluge.client.web.get_host_status(r.getId(), {
success: this.onGetHostStatus, success: this.onGetHostStatus,
scope: this scope: this
}); });
@ -171,21 +157,23 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
* @param {Ext.data.Record} record The hosts record to update the UI for * @param {Ext.data.Record} record The hosts record to update the UI for
*/ */
updateButtons: function(record) { updateButtons: function(record) {
var button = this.buttons[1], status = record.get('status'); var btns = this.query('toolbar[dock=bottom] button'),
btn = btns[4],
s = record.get('status');
// Update the Connect/Disconnect button // Update the Connect/Disconnect button
if (status == _('Connected')) { if (s == _('Connected')) {
button.enable(); btn.enable();
button.setText(_('Disconnect')); btn.setText(_('Disconnect'));
} else if (status == _('Offline')) { } else if (s == _('Offline')) {
button.disable(); btn.disable();
} else { } else {
button.enable(); btn.enable();
button.setText(_('Connect')); btn.setText(_('Connect'));
} }
// Update the Stop/Start Daemon button // Update the Stop/Start Daemon button
if (status == _('Offline')) { if (s == _('Offline')) {
if (record.get('host') == '127.0.0.1' || record.get('host') == 'localhost') { if (record.get('host') == '127.0.0.1' || record.get('host') == 'localhost') {
this.stopHostButton.enable(); this.stopHostButton.enable();
this.stopHostButton.setText(_('Start Daemon')); this.stopHostButton.setText(_('Start Daemon'));
@ -201,7 +189,7 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
// private // private
onAddClick: function(button, e) { onAddClick: function(button, e) {
if (!this.addWindow) { if (!this.addWindow) {
this.addWindow = new Deluge.AddConnectionWindow(); this.addWindow = Ext.create('Deluge.AddConnectionWindow');
this.addWindow.on('hostadded', this.onHostAdded, this); this.addWindow.on('hostadded', this.onHostAdded, this);
} }
this.addWindow.show(); this.addWindow.show();
@ -219,7 +207,9 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
// private // private
onConnect: function(e) { onConnect: function(e) {
var selected = this.list.getSelectedRecords()[0]; var sm = this.grid.getSelectionModel(),
selected = sm.getLastSelected();
if (!selected) return; if (!selected) return;
if (selected.get('status') == _('Connected')) { if (selected.get('status') == _('Connected')) {
@ -231,8 +221,7 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
scope: this scope: this
}); });
} else { } else {
var id = selected.id; deluge.client.web.connect(selected.getId(), {
deluge.client.web.connect(id, {
success: function(methods) { success: function(methods) {
deluge.client.reloadMethods(); deluge.client.reloadMethods();
deluge.client.on('connected', function(e) { deluge.client.on('connected', function(e) {
@ -246,9 +235,13 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
// private // private
onGetHosts: function(hosts) { onGetHosts: function(hosts) {
this.list.getStore().loadData(hosts); // FIXME: Why on earth do I need to do it like this?!
var store = this.grid.getStore(),
results = store.proxy.reader.readRecords(hosts);
store.loadRecords(results.records);
Ext.each(hosts, function(host) { Ext.each(hosts, function(host) {
deluge.client.web.get_host_status(host[0], { deluge.client.web.get_host_status(host['id'], {
success: this.onGetHostStatus, success: this.onGetHostStatus,
scope: this scope: this
}); });
@ -257,15 +250,18 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
// private // private
onGetHostStatus: function(host) { onGetHostStatus: function(host) {
var record = this.list.getStore().getById(host[0]); var record = this.grid.getStore().getById(host['id']);
record.set('status', host[3]) record.set('status', host['status'])
record.set('version', host[4]) record.set('version', host['version'])
record.commit(); record.commit();
if (this.list.getSelectedRecords()[0] == record) this.updateButtons(record);
if (this.grid.getSelectionModel().isSelected(record)) {
this.updateButtons(record);
}
}, },
// private // private
onHide: function() { afterHidden: function() {
if (this.running) window.clearInterval(this.running); if (this.running) window.clearInterval(this.running);
}, },
@ -298,10 +294,12 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
// private // private
onRemoveClick: function(button) { onRemoveClick: function(button) {
var connection = this.list.getSelectedRecords()[0]; var sm = this.grid.getSelectionModel(),
if (!connection) return; selected = sm.getLastSelected();
deluge.client.web.remove_host(connection.id, { if (!selected) return;
deluge.client.web.remove_host(selected.getId(), {
success: function(result) { success: function(result) {
if (!result) { if (!result) {
Ext.MessageBox.show({ Ext.MessageBox.show({
@ -313,7 +311,7 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
iconCls: 'x-deluge-icon-error' iconCls: 'x-deluge-icon-error'
}); });
} else { } else {
this.list.getStore().remove(connection); this.grid.getStore().remove(selected);
} }
}, },
scope: this scope: this
@ -321,12 +319,12 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
}, },
// private // private
onSelectionChanged: function(list, selections) { onSelectionChanged: function(grid, selections) {
if (selections[0]) { if (selections[0]) {
this.removeHostButton.enable(); this.removeHostButton.enable();
this.stopHostButton.enable(); this.stopHostButton.enable();
this.stopHostButton.setText(_('Stop Daemon')); this.stopHostButton.setText(_('Stop Daemon'));
this.updateButtons(this.list.getRecord(selections[0])); this.updateButtons(selections[0]);
} else { } else {
this.removeHostButton.disable(); this.removeHostButton.disable();
this.stopHostButton.disable(); this.stopHostButton.disable();
@ -335,12 +333,12 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
// FIXME: Find out why this is being fired twice // FIXME: Find out why this is being fired twice
// private // private
onShow: function() { afterShown: function() {
if (!this.addHostButton) { if (!this.addHostButton) {
var bbar = this.panel.getBottomToolbar(); var buttons = this.grid.query('button');
this.addHostButton = bbar.items.get('cm-add'); this.addHostButton = buttons[0];
this.removeHostButton = bbar.items.get('cm-remove'); this.removeHostButton = buttons[1];
this.stopHostButton = bbar.items.get('cm-stop'); this.stopHostButton = buttons[2];
} }
this.loadHosts(); this.loadHosts();
if (this.running) return; if (this.running) return;
@ -349,15 +347,16 @@ Deluge.ConnectionManager = Ext.extend(Ext.Window, {
// private // private
onStopClick: function(button, e) { onStopClick: function(button, e) {
var connection = this.list.getSelectedRecords()[0]; var sm = this.grid.getSelectionModel(),
if (!connection) return; selected = sm.getLastSelected();
if (!selected) return;
if (connection.get('status') == 'Offline') { if (selected.get('status') == 'Offline') {
// This means we need to start the daemon // This means we need to start the daemon
deluge.client.web.start_daemon(connection.get('port')); deluge.client.web.start_daemon(selected.get('port'));
} else { } else {
// This means we need to stop the daemon // This means we need to stop the daemon
deluge.client.web.stop_daemon(connection.id, { deluge.client.web.stop_daemon(selected.getId(), {
success: function(result) { success: function(result) {
if (!result[0]) { if (!result[0]) {
Ext.MessageBox.show({ Ext.MessageBox.show({

View File

@ -31,7 +31,14 @@
*/ */
// Setup the state manager // Setup the state manager
Ext.state.Manager.setProvider(new Ext.state.CookieProvider()); var provider = Ext.state.CookieProvider;
try {
if ('localStorage' in window && window['localStorage'] !== null) {
provider = Ext.state.LocalStorageProvider;
}
} catch (e) {
}
Ext.state.Manager.setProvider(new provider());
// Add some additional functions to ext and setup some of the // Add some additional functions to ext and setup some of the
// configurable parameters // configurable parameters
@ -92,16 +99,10 @@ Ext.apply(Deluge, {
pluginStore: {}, pluginStore: {},
// private // private
progressTpl: '<div class="x-progress-wrap x-progress-renderered">' + progressTpl: '<div class="x-progress x-progress-default">' +
'<div class="x-progress-inner">' + '<div class="x-progress-text x-progress-text-back" style="width: {1}px;">{0}</div>' +
'<div style="width: {2}px" class="x-progress-bar">' + '<div class="x-progress-bar" style="width: {3}px;">' +
'<div style="z-index: 99; width: {3}px" class="x-progress-text">' + '<div class="x-progress-text" style="width: {1}px;">{0}</div>' +
'<div style="width: {1}px;">{0}</div>' +
'</div>' +
'</div>' +
'<div class="x-progress-text x-progress-text-back">' +
'<div style="width: {1}px;">{0}</div>' +
'</div>' +
'</div>' + '</div>' +
'</div>', '</div>',
@ -115,11 +116,11 @@ Ext.apply(Deluge, {
* @param {Number} modified Amount to subtract from the width allowing for fixes * @param {Number} modified Amount to subtract from the width allowing for fixes
*/ */
progressBar: function(progress, width, text, modifier) { progressBar: function(progress, width, text, modifier) {
modifier = Ext.value(modifier, 10); modifier = Ext.value(modifier, 5);
var progressWidth = ((width / 100.0) * progress).toFixed(0); var progressWidth = ((width / 100.0) * progress).toFixed(0);
var barWidth = progressWidth - 1; var barWidth = progressWidth - 1;
var textWidth = ((progressWidth - modifier) > 0 ? progressWidth - modifier : 0); var textWidth = ((progressWidth - modifier) > 0 ? progressWidth - modifier : 0);
return String.format(Deluge.progressTpl, text, width, barWidth, textWidth); return Ext.String.format(Deluge.progressTpl, text, width, barWidth, textWidth);
}, },
/** /**
@ -152,6 +153,13 @@ Ext.apply(Deluge, {
// Setup a space for plugins to insert themselves // Setup a space for plugins to insert themselves
deluge.plugins = {}; deluge.plugins = {};
deluge.logDateFormat = 'd/m/Y H:i:s,u';
deluge.log = function(msg) {
var date = new Date()
console.log(Ext.Date.format(date, deluge.logDateFormat) + ' - ' + msg);
}
// Hinting for gettext_gen.py // Hinting for gettext_gen.py
// _('Do Not Download') // _('Do Not Download')
// _('Normal Priority') // _('Normal Priority')

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.EditTrackerWindow.js * Deluge.EditTrackerWindow.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,13 +29,13 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.ns('Deluge');
/** /**
* @class Deluge.EditTrackerWindow * @class Deluge.EditTrackerWindow
* @extends Ext.Window * @extends Ext.Window
*/ */
Deluge.EditTrackerWindow = Ext.extend(Ext.Window, { Ext.define('Deluge.EditTrackerWindow', {
extend: 'Ext.Window',
title: _('Edit Tracker'), title: _('Edit Tracker'),
layout: 'fit', layout: 'fit',
@ -51,10 +51,10 @@ Deluge.EditTrackerWindow = Ext.extend(Ext.Window, {
iconCls: 'x-deluge-edit-trackers', iconCls: 'x-deluge-edit-trackers',
initComponent: function() { initComponent: function() {
Deluge.EditTrackerWindow.superclass.initComponent.call(this); this.callParent(arguments);
this.addButton(_('Cancel'), this.onCancelClick, this); //this.addButton(_('Cancel'), this.onCancelClick, this);
this.addButton(_('Save'), this.onSaveClick, this); //this.addButton(_('Save'), this.onSaveClick, this);
this.on('hide', this.onHide, this); this.on('hide', this.onHide, this);
this.form = this.add({ this.form = this.add({
@ -71,7 +71,7 @@ Deluge.EditTrackerWindow = Ext.extend(Ext.Window, {
}, },
show: function(record) { show: function(record) {
Deluge.EditTrackerWindow.superclass.show.call(this); this.callParent(arguments);
this.record = record; this.record = record;
this.form.getForm().findField('tracker').setValue(record.data['url']); this.form.getForm().findField('tracker').setValue(record.data['url']);

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.EditTrackers.js * Deluge.EditTrackers.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,13 +29,13 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.ns('Deluge');
/** /**
* @class Deluge.EditTrackerWindow * @class Deluge.EditTrackerWindow
* @extends Ext.Window * @extends Ext.Window
*/ */
Deluge.EditTrackersWindow = Ext.extend(Ext.Window, { Ext.define('Deluge.EditTrackersWindow', {
extend: 'Ext.Window',
title: _('Edit Trackers'), title: _('Edit Trackers'),
layout: 'fit', layout: 'fit',
@ -51,21 +51,20 @@ Deluge.EditTrackersWindow = Ext.extend(Ext.Window, {
iconCls: 'x-deluge-edit-trackers', iconCls: 'x-deluge-edit-trackers',
initComponent: function() { initComponent: function() {
Deluge.EditTrackersWindow.superclass.initComponent.call(this); this.callParent(arguments);
this.addButton(_('Cancel'), this.onCancelClick, this); //this.addButton(_('Cancel'), this.onCancelClick, this);
this.addButton(_('Ok'), this.onOkClick, this); //this.addButton(_('Ok'), this.onOkClick, this);
this.addEvents('save'); this.addEvents('save');
this.on('show', this.onShow, this); this.on('show', this.onShow, this);
this.on('save', this.onSave, this);
this.addWindow = new Deluge.AddTrackerWindow(); this.addWindow = Ext.create('Deluge.AddTrackerWindow');
this.addWindow.on('add', this.onAddTrackers, this); this.addWindow.on('add', this.onAddTrackers, this);
this.editWindow = new Deluge.EditTrackerWindow(); this.editWindow = Ext.create('Deluge.EditTrackerWindow');
this.list = new Ext.list.ListView({ this.list = Ext.create('Ext.list.ListView', {
store: new Ext.data.JsonStore({ store: Ext.create('Ext.data.Store', {
root: 'trackers', root: 'trackers',
fields: [ fields: [
'tier', 'tier',
@ -96,7 +95,7 @@ Deluge.EditTrackersWindow = Ext.extend(Ext.Window, {
margins: '0 0 0 0', margins: '0 0 0 0',
items: [this.list], items: [this.list],
autoScroll: true, autoScroll: true,
bbar: new Ext.Toolbar({ bbar: {
items: [ items: [
{ {
text: _('Up'), text: _('Up'),
@ -125,7 +124,7 @@ Deluge.EditTrackersWindow = Ext.extend(Ext.Window, {
scope: this scope: this
} }
] ]
}) }
}); });
}, },
@ -147,7 +146,7 @@ Deluge.EditTrackersWindow = Ext.extend(Ext.Window, {
} }
}, this); }, this);
if (duplicate) return; if (duplicate) return;
store.add(new store.recordType({'tier': heightestTier + 1, 'url': tracker})); store.add({'tier': heightestTier + 1, 'url': tracker});
}, this); }, this);
}, },
@ -194,6 +193,10 @@ Deluge.EditTrackersWindow = Ext.extend(Ext.Window, {
this.list.getStore().sort('tier', 'ASC'); this.list.getStore().sort('tier', 'ASC');
}, },
onSave: function() {
// What am I meant to do here?
},
onSaveFail: function() { onSaveFail: function() {
}, },

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.EventsManager.js * Deluge.EventsManager.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -36,11 +36,13 @@
* <p>Deluge.EventsManager is instantated as <tt>deluge.events</tt> and can be used by components of the UI to fire global events</p> * <p>Deluge.EventsManager is instantated as <tt>deluge.events</tt> and can be used by components of the UI to fire global events</p>
* Class for holding global events that occur within the UI. * Class for holding global events that occur within the UI.
*/ */
Deluge.EventsManager = Ext.extend(Ext.util.Observable, { Ext.define('Deluge.EventsManager', {
extend: 'Ext.util.Observable',
toRegister: [],
constructor: function() { constructor: function() {
this.toRegister = [];
this.on('login', this.onLogin, this); this.on('login', this.onLogin, this);
Deluge.EventsManager.superclass.constructor.call(this); this.callParent(arguments);
}, },
/** /**
@ -54,8 +56,9 @@ Deluge.EventsManager = Ext.extend(Ext.util.Observable, {
} else { } else {
deluge.client.web.register_event_listener(eventName); deluge.client.web.register_event_listener(eventName);
} }
} else {
this.callParent(arguments);
} }
Deluge.EventsManager.superclass.addListener.call(this, eventName, fn, scope, o);
}, },
getEvents: function() { getEvents: function() {
@ -124,4 +127,3 @@ Deluge.EventsManager.prototype.on = Deluge.EventsManager.prototype.addListener
* @method * @method
*/ */
Deluge.EventsManager.prototype.fire = Deluge.EventsManager.prototype.fireEvent Deluge.EventsManager.prototype.fire = Deluge.EventsManager.prototype.fireEvent
deluge.events = new Deluge.EventsManager();

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.FilterPanel.js * Deluge.FilterPanel.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,24 +29,35 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.ns('Deluge');
/** /**
* @class Deluge.FilterPanel * @class Deluge.FilterPanel
* @extends Ext.list.ListView * @extends Ext.panel.Panel
*/ */
Deluge.FilterPanel = Ext.extend(Ext.Panel, { Ext.define('Deluge.FilterPanel', {
extend: 'Ext.panel.Panel',
autoScroll: true, autoScroll: true,
border: false, border: false,
show_zero: null, show_zero: null,
title: ' ',
initComponent: function() { initComponent: function() {
Deluge.FilterPanel.superclass.initComponent.call(this); this.callParent(arguments);
this.filterType = this.initialConfig.filter; this.filterType = this.initialConfig.filter;
this.on('activate', function() {
console.log('activate');
});
this.on('show', function() {
console.log('show');
});
this.on('render', function() {
console.log('render');
});
var title = this.filterType.replace('_', ' '), var title = this.filterType.replace('_', ' '),
parts = title.split(' '), parts = title.split(' '),
title = ''; title = '';
@ -54,7 +65,7 @@ Deluge.FilterPanel = Ext.extend(Ext.Panel, {
fl = p.substring(0, 1).toUpperCase(); fl = p.substring(0, 1).toUpperCase();
title += fl + p.substring(1) + ' '; title += fl + p.substring(1) + ' ';
}); });
this.setTitle(_(title)); this.title = _(title);
if (Deluge.FilterPanel.templates[this.filterType]) { if (Deluge.FilterPanel.templates[this.filterType]) {
var tpl = Deluge.FilterPanel.templates[this.filterType]; var tpl = Deluge.FilterPanel.templates[this.filterType];
@ -62,23 +73,31 @@ Deluge.FilterPanel = Ext.extend(Ext.Panel, {
var tpl = '<div class="x-deluge-filter x-deluge-{filter:lowercase}">{filter} ({count})</div>'; var tpl = '<div class="x-deluge-filter x-deluge-{filter:lowercase}">{filter} ({count})</div>';
} }
this.list = this.add({ this.grid = this.add({
xtype: 'listview', xtype: 'grid',
border: false,
singleSelect: true, singleSelect: true,
hideHeaders: true, hideHeaders: true,
reserveScrollOffset: true, reserveScrollOffset: true,
store: new Ext.data.ArrayStore({ store: Ext.create('Ext.data.Store', {
idIndex: 0, model: 'Deluge.data.Filter',
fields: ['filter', 'count'] proxy: {
type: 'memory'
}
}), }),
columns: [{ columns: [{
id: 'filter', xtype: 'templatecolumn',
sortable: false, sortable: false,
tpl: tpl, tpl: tpl,
dataIndex: 'filter' dataIndex: 'filter',
flex: 1
}] }]
}); });
this.relayEvents(this.list, ['selectionchange']); this.relayEvents(this.grid, ['selectionchange']);
},
getSelectionModel: function() {
return this.grid.getSelectionModel();
}, },
/** /**
@ -86,11 +105,13 @@ Deluge.FilterPanel = Ext.extend(Ext.Panel, {
* @returns {String} the current filter state * @returns {String} the current filter state
*/ */
getState: function() { getState: function() {
if (!this.list.getSelectionCount()) return; var sm = this.grid.getSelectionModel()
if (!sm.hasSelection()) return;
var state = this.list.getSelectedRecords()[0]; var state = sm.getLastSelected(),
if (state.id == 'All') return; stateId = state.getId();
return state.id; if (stateId == 'All') return;
return stateId;
}, },
/** /**
@ -105,7 +126,7 @@ Deluge.FilterPanel = Ext.extend(Ext.Panel, {
* @returns {Ext.data.Store} the ListView store * @returns {Ext.data.Store} the ListView store
*/ */
getStore: function() { getStore: function() {
return this.list.getStore(); return this.grid.getStore();
}, },
/** /**
@ -128,41 +149,44 @@ Deluge.FilterPanel = Ext.extend(Ext.Panel, {
states = newStates; states = newStates;
} }
var store = this.getStore(); var store = this.getStore(),
var filters = {}; sm = this.grid.getSelectionModel(),
filters = {};
Ext.each(states, function(s, i) { Ext.each(states, function(s, i) {
var record = store.getById(s[0]); var record = store.getById(s[0]);
if (!record) { if (!record) {
record = new store.recordType({ record = Ext.create('Deluge.data.Filter', {
filter: s[0], filter: s[0],
count: s[1] count: [1]
}); });
record.id = s[0]; record.setId(s[0]);
store.insert(i, record); store.insert(i, [record]);
} } else {
record.beginEdit(); record.beginEdit();
record.set('filter', s[0]); record.set('filter', s[0]);
record.set('count', s[1]); record.set('count', s[1]);
record.endEdit(); record.endEdit();
}
filters[s[0]] = true; filters[s[0]] = true;
}, this); }, this);
store.each(function(record) { store.each(function(record) {
if (filters[record.id]) return; if (filters[record.getId()]) return;
var r = this.list.getSelectedRecords()[0]; var r = sm.getLastSelected();
store.remove(record); store.remove(record);
if (r.id == record.id) { if (r === undefined)
this.list.select(0); return;
if (r.getId() == record.getId()) {
sm.select(0);
} }
}, this); }, this);
store.commitChanges(); store.sync();
if (!this.list.getSelectionCount()) { if (!sm.hasSelection()) {
this.list.select(0); //sm.select(0);
} }
} }
}); });
Deluge.FilterPanel.templates = { Deluge.FilterPanel.templates = {

View File

@ -56,7 +56,7 @@ Deluge.Formatters = {
} }
timestamp = timestamp * 1000; timestamp = timestamp * 1000;
var date = new Date(timestamp); var date = new Date(timestamp);
return String.format('{0}/{1}/{2} {3}:{4}:{5}', return Ext.String.format('{0}/{1}/{2} {3}:{4}:{5}',
zeroPad(date.getDate(), 2), zeroPad(date.getMonth() + 1, 2), date.getFullYear(), zeroPad(date.getDate(), 2), zeroPad(date.getMonth() + 1, 2), date.getFullYear(),
zeroPad(date.getHours(), 2), zeroPad(date.getMinutes(), 2), zeroPad(date.getSeconds(), 2)); zeroPad(date.getHours(), 2), zeroPad(date.getMinutes(), 2), zeroPad(date.getSeconds(), 2));
}, },
@ -148,9 +148,9 @@ Deluge.Formatters = {
return value.toLowerCase().replace('.', '_'); return value.toLowerCase().replace('.', '_');
} }
} }
var fsize = Deluge.Formatters.size; window.fsize = Deluge.Formatters.size;
var fspeed = Deluge.Formatters.speed; window.fspeed = Deluge.Formatters.speed;
var ftime = Deluge.Formatters.timeRemaining; window.ftime = Deluge.Formatters.timeRemaining;
var fdate = Deluge.Formatters.date; window.fdate = Deluge.Formatters.date;
var fplain = Deluge.Formatters.plain; window.fplain = Deluge.Formatters.plain;
Ext.util.Format.cssClassEscape = Deluge.Formatters.cssClassEscape; Ext.util.Format.cssClassEscape = Deluge.Formatters.cssClassEscape;

View File

@ -48,7 +48,8 @@ Deluge.Keys = {
'queue', 'name', 'total_size', 'state', 'progress', 'num_seeds', 'queue', 'name', 'total_size', 'state', 'progress', 'num_seeds',
'total_seeds', 'num_peers', 'total_peers', 'download_payload_rate', 'total_seeds', 'num_peers', 'total_peers', 'download_payload_rate',
'upload_payload_rate', 'eta', 'ratio', 'distributed_copies', 'upload_payload_rate', 'eta', 'ratio', 'distributed_copies',
'is_auto_managed', 'time_added', 'tracker_host', 'save_path', 'last_seen_complete' 'is_auto_managed', 'time_added', 'tracker_host', 'save_path',
'last_seen_complete', 'owner', 'public', 'shared'
], ],
/** /**
@ -63,7 +64,7 @@ Deluge.Keys = {
'total_done', 'total_payload_download', 'total_uploaded', 'total_done', 'total_payload_download', 'total_uploaded',
'total_payload_upload', 'next_announce', 'tracker_status', 'num_pieces', 'total_payload_upload', 'next_announce', 'tracker_status', 'num_pieces',
'piece_length', 'is_auto_managed', 'active_time', 'seeding_time', 'piece_length', 'is_auto_managed', 'active_time', 'seeding_time',
'seed_rank', 'last_seen_complete', 'owner', 'public', 'shared' 'seed_rank'
], ],
/** /**
@ -87,7 +88,7 @@ Deluge.Keys = {
*/ */
Details: [ Details: [
'name', 'save_path', 'total_size', 'num_files', 'message', 'name', 'save_path', 'total_size', 'num_files', 'message',
'tracker', 'comment' 'tracker', 'comment', 'owner', 'shared'
], ],
/** /**

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.LoginWindow.js * Deluge.LoginWindow.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -30,7 +30,9 @@
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Deluge.LoginWindow = Ext.extend(Ext.Window, { Ext.define('Deluge.LoginWindow', {
extend: 'Ext.Window',
firstShow: true, firstShow: true,
bodyStyle: 'padding: 10px 5px;', bodyStyle: 'padding: 10px 5px;',
@ -44,35 +46,41 @@ Deluge.LoginWindow = Ext.extend(Ext.Window, {
resizable: false, resizable: false,
title: _('Login'), title: _('Login'),
width: 300, width: 300,
height: 120, height: 105,
initComponent: function() { initComponent: function() {
Deluge.LoginWindow.superclass.initComponent.call(this); this.callParent(arguments);
this.on('show', this.onShow, this); this.on('show', this.onShow, this);
this.addButton({ this.addDocked({
text: _('Login'), xtype: 'toolbar',
handler: this.onLogin, dock: 'bottom',
scope: this defaultType: 'button',
items: [
'->',
{text: _('Login'), handler: this.onLogin, scope: this}
]
}); });
this.form = this.add({ this.form = this.add({
xtype: 'form', xtype: 'form',
baseCls: 'x-plain', baseCls: 'x-plain',
labelWidth: 55,
width: 300, width: 300,
defaults: {width: 200}, items: [{
defaultType: 'textfield'
});
this.passwordField = this.form.add({
xtype: 'textfield', xtype: 'textfield',
fieldLabel: _('Password'), fieldLabel: _('Password'),
id: '_password',
name: 'password', name: 'password',
inputType: 'password' inputType: 'password',
labelWidth: 60,
width: 275,
listeners: {
specialkey: {
scope: this,
fn: this.onSpecialKey
}
}
}]
}); });
this.passwordField.on('specialkey', this.onSpecialKey, this);
}, },
logout: function() { logout: function() {
@ -92,7 +100,7 @@ Deluge.LoginWindow = Ext.extend(Ext.Window, {
} }
if (skipCheck) { if (skipCheck) {
return Deluge.LoginWindow.superclass.show.call(this); return this.callParent();
} }
deluge.client.auth.check_session({ deluge.client.auth.check_session({
@ -115,13 +123,14 @@ Deluge.LoginWindow = Ext.extend(Ext.Window, {
}, },
onLogin: function() { onLogin: function() {
var passwordField = this.passwordField; var f = this.form.getForm(),
deluge.client.auth.login(passwordField.getValue(), { p = f.getValues().password;;
deluge.client.auth.login(p, {
success: function(result) { success: function(result) {
if (result) { if (result) {
deluge.events.fire('login'); deluge.events.fire('login');
this.hide(); this.hide();
passwordField.setRawValue(''); f.setValues({password: ''});
} else { } else {
Ext.MessageBox.show({ Ext.MessageBox.show({
title: _('Login Failed'), title: _('Login Failed'),
@ -129,7 +138,7 @@ Deluge.LoginWindow = Ext.extend(Ext.Window, {
buttons: Ext.MessageBox.OK, buttons: Ext.MessageBox.OK,
modal: false, modal: false,
fn: function() { fn: function() {
passwordField.focus(true, 10); f.findField('password').focus(true, 10);
}, },
icon: Ext.MessageBox.WARNING, icon: Ext.MessageBox.WARNING,
iconCls: 'x-deluge-icon-warning' iconCls: 'x-deluge-icon-warning'
@ -148,6 +157,6 @@ Deluge.LoginWindow = Ext.extend(Ext.Window, {
}, },
onShow: function() { onShow: function() {
this.passwordField.focus(true, true); this.form.getForm().findField('password').focus(true, 10);
} }
}); });

View File

@ -81,7 +81,7 @@ deluge.menus = {
} }
} }
deluge.menus.torrent = new Ext.menu.Menu({ deluge.menus.torrent = Ext.create('Ext.menu.Menu', {
id: 'torrentMenu', id: 'torrentMenu',
items: [{ items: [{
torrentAction: 'pause', torrentAction: 'pause',
@ -98,11 +98,11 @@ deluge.menus.torrent = new Ext.menu.Menu({
}, '-', { }, '-', {
text: _('Options'), text: _('Options'),
iconCls: 'icon-options', iconCls: 'icon-options',
menu: new Ext.menu.Menu({ menu: {
items: [{ items: [{
text: _('D/L Speed Limit'), text: _('D/L Speed Limit'),
iconCls: 'x-deluge-downloading', iconCls: 'x-deluge-downloading',
menu: new Ext.menu.Menu({ menu: {
items: [{ items: [{
text: _('5 KiB/s') text: _('5 KiB/s')
}, { }, {
@ -116,11 +116,11 @@ deluge.menus.torrent = new Ext.menu.Menu({
},{ },{
text: _('Unlimited') text: _('Unlimited')
}] }]
}) }
}, { }, {
text: _('U/L Speed Limit'), text: _('U/L Speed Limit'),
iconCls: 'x-deluge-seeding', iconCls: 'x-deluge-seeding',
menu: new Ext.menu.Menu({ menu: {
items: [{ items: [{
text: _('5 KiB/s') text: _('5 KiB/s')
}, { }, {
@ -134,11 +134,11 @@ deluge.menus.torrent = new Ext.menu.Menu({
},{ },{
text: _('Unlimited') text: _('Unlimited')
}] }]
}) }
}, { }, {
text: _('Connection Limit'), text: _('Connection Limit'),
iconCls: 'x-deluge-connections', iconCls: 'x-deluge-connections',
menu: new Ext.menu.Menu({ menu: {
items: [{ items: [{
text: _('50') text: _('50')
}, { }, {
@ -152,11 +152,11 @@ deluge.menus.torrent = new Ext.menu.Menu({
},{ },{
text: _('Unlimited') text: _('Unlimited')
}] }]
}) }
}, { }, {
text: _('Upload Slot Limit'), text: _('Upload Slot Limit'),
iconCls: 'icon-upload-slots', iconCls: 'icon-upload-slots',
menu: new Ext.menu.Menu({ menu: {
items: [{ items: [{
text: _('0') text: _('0')
}, { }, {
@ -170,17 +170,17 @@ deluge.menus.torrent = new Ext.menu.Menu({
},{ },{
text: _('Unlimited') text: _('Unlimited')
}] }]
}) }
}, { }, {
id: 'auto_managed', id: 'auto_managed',
text: _('Auto Managed'), text: _('Auto Managed'),
checked: false checked: false
}] }]
}) }
}, '-', { }, '-', {
text: _('Queue'), text: _('Queue'),
iconCls: 'icon-queue', iconCls: 'icon-queue',
menu: new Ext.menu.Menu({ menu: {
items: [{ items: [{
torrentAction: 'top', torrentAction: 'top',
text: _('Top'), text: _('Top'),
@ -206,7 +206,7 @@ deluge.menus.torrent = new Ext.menu.Menu({
handler: deluge.menus.onTorrentAction, handler: deluge.menus.onTorrentAction,
scope: deluge.menus scope: deluge.menus
}] }]
}) }
}, '-', { }, '-', {
torrentAction: 'update', torrentAction: 'update',
text: _('Update Tracker'), text: _('Update Tracker'),
@ -240,7 +240,7 @@ deluge.menus.torrent = new Ext.menu.Menu({
}] }]
}); });
deluge.menus.filePriorities = new Ext.menu.Menu({ deluge.menus.filePriorities = Ext.create('Ext.menu.Menu', {
id: 'filePrioritiesMenu', id: 'filePrioritiesMenu',
items: [{ items: [{
id: 'expandAll', id: 'expandAll',

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.MoveStorage.js * Deluge.MoveStorage.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -30,11 +30,9 @@
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.namespace('Deluge'); Ext.define('Deluge.MoveStorage', {
Deluge.MoveStorage = Ext.extend(Ext.Window, { extend: 'Ext.Window',
constructor: function(config) {
config = Ext.apply({
title: _('Move Storage'), title: _('Move Storage'),
width: 375, width: 375,
height: 110, height: 110,
@ -44,16 +42,14 @@ Deluge.MoveStorage = Ext.extend(Ext.Window, {
closable: true, closable: true,
iconCls: 'x-deluge-move-storage', iconCls: 'x-deluge-move-storage',
plain: true, plain: true,
resizable: false resizable: false,
}, config);
Deluge.MoveStorage.superclass.constructor.call(this, config);
},
initComponent: function() { initComponent: function() {
Deluge.MoveStorage.superclass.initComponent.call(this); this.callParent(arguments);
this.addButton(_('Cancel'), this.onCancel, this); // FIXME: Replace the buttons
this.addButton(_('Move'), this.onMove, this); //this.addButton(_('Cancel'), this.onCancel, this);
//this.addButton(_('Move'), this.onMove, this);
this.form = this.add({ this.form = this.add({
xtype: 'form', xtype: 'form',
@ -82,12 +78,12 @@ Deluge.MoveStorage = Ext.extend(Ext.Window, {
}, },
hide: function() { hide: function() {
Deluge.MoveStorage.superclass.hide.call(this); this.callParent(arguments);
this.torrentIds = null; this.torrentIds = null;
}, },
show: function(torrentIds) { show: function(torrentIds) {
Deluge.MoveStorage.superclass.show.call(this); this.callParent(arguments);
this.torrentIds = torrentIds; this.torrentIds = torrentIds;
}, },
@ -101,4 +97,3 @@ Deluge.MoveStorage = Ext.extend(Ext.Window, {
this.hide(); this.hide();
} }
}); });
deluge.moveStorage = new Deluge.MoveStorage();

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.OtherLimitWindow.js * Deluge.OtherLimitWindow.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,13 +29,13 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.ns('Deluge');
/** /**
* @class Deluge.OtherLimitWindow * @class Deluge.OtherLimitWindow
* @extends Ext.Window * @extends Ext.Window
*/ */
Deluge.OtherLimitWindow = Ext.extend(Ext.Window, { Ext.define('Deluge.OtherLimitWindow', {
extend: 'Ext.Window',
layout: 'fit', layout: 'fit',
width: 210, width: 210,
@ -44,7 +44,7 @@ Deluge.OtherLimitWindow = Ext.extend(Ext.Window, {
closeAction: 'hide', closeAction: 'hide',
initComponent: function() { initComponent: function() {
Deluge.OtherLimitWindow.superclass.initComponent.call(this); this.callParent(arguments);
this.form = this.add({ this.form = this.add({
xtype: 'form', xtype: 'form',
baseCls: 'x-plain', baseCls: 'x-plain',
@ -69,8 +69,17 @@ Deluge.OtherLimitWindow = Ext.extend(Ext.Window, {
this.setSize(180, 100); this.setSize(180, 100);
} }
this.addButton(_('Cancel'), this.onCancelClick, this); this.addDocked({
this.addButton(_('Ok'), this.onOkClick, this); xtype: 'toolbar',
dock: 'bottom',
defaultType: 'button',
items: [
'->',
{text: _('Cancel'), handler: this.onCancelClick, scope: this},
{text: _('Ok'), handler: this.onOkClick, scope: this}
]
});
this.afterMethod('show', this.doFocusField, this); this.afterMethod('show', this.doFocusField, this);
}, },

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.Plugin.js * Deluge.Plugin.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,13 +29,13 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.ns('Deluge');
/** /**
* @class Deluge.Plugin * @class Deluge.Plugin
* @extends Ext.util.Observable * @extends Ext.util.Observable
*/ */
Deluge.Plugin = Ext.extend(Ext.util.Observable, { Ext.define('Deluge.Plugin', {
extend: 'Ext.util.Observable',
/** /**
* The plugins name * The plugins name
@ -59,7 +59,7 @@ Deluge.Plugin = Ext.extend(Ext.util.Observable, {
*/ */
"disabled": true "disabled": true
}); });
Deluge.Plugin.superclass.constructor.call(this, config); this.callParent(arguments);
}, },
/** /**

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.RemoveWindow.js * Deluge.RemoveWindow.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -34,7 +34,8 @@
* @class Deluge.RemoveWindow * @class Deluge.RemoveWindow
* @extends Ext.Window * @extends Ext.Window
*/ */
Deluge.RemoveWindow = Ext.extend(Ext.Window, { Ext.define('Deluge.RemoveWindow', {
extend: 'Ext.Window',
title: _('Remove Torrent'), title: _('Remove Torrent'),
layout: 'fit', layout: 'fit',
@ -45,16 +46,25 @@ Deluge.RemoveWindow = Ext.extend(Ext.Window, {
closeAction: 'hide', closeAction: 'hide',
closable: true, closable: true,
iconCls: 'x-deluge-remove-window-icon', iconCls: 'x-deluge-remove-window-icon',
plain: true,
bodyStyle: 'padding: 5px; padding-left: 10px;',
html: 'Are you sure you wish to remove the torrent (s)?',
initComponent: function() { initComponent: function() {
Deluge.RemoveWindow.superclass.initComponent.call(this); this.callParent(arguments);
this.addButton(_('Cancel'), this.onCancel, this); this.addDocked({
this.addButton(_('Remove With Data'), this.onRemoveData, this); xtype: 'toolbar',
this.addButton(_('Remove Torrent'), this.onRemove, this); dock: 'bottom',
defaultType: 'button',
items: [
'->',
{text: _('Cancel'), handler: this.onCancel, scope: this},
{text: _('Remove With Data'), handler: this.onRemoveData, scope: this},
{text: _('Remove Torrent'), handler: this.onRemove, scope: this}
]
});
this.add({
bodyStyle: 'padding: 10px;',
border: false,
html: 'Are you sure you wish to remove the torrent (s)?',
});
}, },
remove: function(removeData) { remove: function(removeData) {
@ -71,7 +81,7 @@ Deluge.RemoveWindow = Ext.extend(Ext.Window, {
}, },
show: function(ids) { show: function(ids) {
Deluge.RemoveWindow.superclass.show.call(this); this.callParent(arguments);
this.torrentIds = ids; this.torrentIds = ids;
}, },
@ -94,5 +104,3 @@ Deluge.RemoveWindow = Ext.extend(Ext.Window, {
deluge.ui.update(); deluge.ui.update();
} }
}); });
deluge.removeWindow = new Deluge.RemoveWindow();

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.Sidebar.js * Deluge.Sidebar.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -39,7 +39,24 @@
* @author Damien Churchill <damoxc@gmail.com> * @author Damien Churchill <damoxc@gmail.com>
* @version 1.3 * @version 1.3
*/ */
Deluge.Sidebar = Ext.extend(Ext.Panel, { Ext.define('Deluge.Sidebar', {
extend: 'Ext.panel.Panel',
id: 'sidebar',
region: 'west',
cls: 'deluge-sidebar',
title: _('Filters'),
layout: 'accordion',
layoutCfg: {
multi: true,
collapseFirst: true
},
split: true,
width: 200,
minSize: 175,
collapsible: true,
margins: '5 0 0 5',
cmargins: '5 0 0 5',
// private // private
panels: {}, panels: {},
@ -47,31 +64,14 @@ Deluge.Sidebar = Ext.extend(Ext.Panel, {
// private // private
selected: null, selected: null,
constructor: function(config) {
config = Ext.apply({
id: 'sidebar',
region: 'west',
cls: 'deluge-sidebar',
title: _('Filters'),
layout: 'accordion',
split: true,
width: 200,
minSize: 175,
collapsible: true,
margins: '5 0 0 5',
cmargins: '5 0 0 5'
}, config);
Deluge.Sidebar.superclass.constructor.call(this, config);
},
// private // private
initComponent: function() { initComponent: function() {
Deluge.Sidebar.superclass.initComponent.call(this); this.callParent(arguments);
deluge.events.on("disconnect", this.onDisconnect, this); deluge.events.on("disconnect", this.onDisconnect, this);
}, },
createFilter: function(filter, states) { createFilter: function(filter, states) {
var panel = new Deluge.FilterPanel({ var panel = Ext.create('Deluge.FilterPanel', {
filter: filter filter: filter
}); });
panel.on('selectionchange', function(view, nodes) { panel.on('selectionchange', function(view, nodes) {
@ -83,11 +83,15 @@ Deluge.Sidebar = Ext.extend(Ext.Panel, {
this.panels[filter] = panel; this.panels[filter] = panel;
panel.header.on('click', function(header) { panel.header.on('click', function(header) {
var s = panel.getStore(),
sm = panel.getSelectionModel();
if (!deluge.config.sidebar_multiple_filters) { if (!deluge.config.sidebar_multiple_filters) {
deluge.ui.update(); deluge.ui.update();
} }
if (!panel.list.getSelectionCount()) {
panel.list.select(0); if (!sm.hasSelection() && s.count() > 0) {
sm.select([s.first()]);
} }
}); });
this.fireEvent('filtercreate', this, panel); this.fireEvent('filtercreate', this, panel);

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.Statusbar.js * Deluge.Statusbar.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,20 +29,16 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.namespace('Deluge');
Deluge.Statusbar = Ext.extend(Ext.ux.StatusBar, { Ext.define('Deluge.StatusBar', {
constructor: function(config) { extend: 'Ext.ux.statusbar.StatusBar',
config = Ext.apply({
id: 'deluge-statusbar', id: 'deluge-statusbar',
defaultIconCls: 'x-deluge-statusbar x-not-connected', defaultIconCls: 'x-deluge-statusbar x-not-connected',
defaultText: _('Not Connected') defaultText: _('Not Connected'),
}, config);
Deluge.Statusbar.superclass.constructor.call(this, config);
},
initComponent: function() { initComponent: function() {
Deluge.Statusbar.superclass.initComponent.call(this); this.callParent(arguments);
deluge.events.on('connect', this.onConnect, this); deluge.events.on('connect', this.onConnect, this);
deluge.events.on('disconnect', this.onDisconnect, this); deluge.events.on('disconnect', this.onDisconnect, this);
@ -55,7 +51,7 @@ Deluge.Statusbar = Ext.extend(Ext.ux.StatusBar, {
cls: 'x-btn-text-icon', cls: 'x-btn-text-icon',
iconCls: 'x-deluge-connections', iconCls: 'x-deluge-connections',
tooltip: _('Connections'), tooltip: _('Connections'),
menu: new Deluge.StatusbarMenu({ menu: Ext.create('Deluge.StatusbarMenu', {
items: [{ items: [{
text: '50', text: '50',
value: '50', value: '50',
@ -102,7 +98,7 @@ Deluge.Statusbar = Ext.extend(Ext.ux.StatusBar, {
cls: 'x-btn-text-icon', cls: 'x-btn-text-icon',
iconCls: 'x-deluge-downloading', iconCls: 'x-deluge-downloading',
tooltip: _('Download Speed'), tooltip: _('Download Speed'),
menu: new Deluge.StatusbarMenu({ menu: Ext.create('Deluge.StatusbarMenu', {
items: [{ items: [{
value: '5', value: '5',
text: '5 KiB/s', text: '5 KiB/s',
@ -150,7 +146,7 @@ Deluge.Statusbar = Ext.extend(Ext.ux.StatusBar, {
cls: 'x-btn-text-icon', cls: 'x-btn-text-icon',
iconCls: 'x-deluge-seeding', iconCls: 'x-deluge-seeding',
tooltip: _('Upload Speed'), tooltip: _('Upload Speed'),
menu: new Deluge.StatusbarMenu({ menu: Ext.create('Deluge.StatusbarMenu', {
items: [{ items: [{
value: '5', value: '5',
text: '5 KiB/s', text: '5 KiB/s',
@ -252,12 +248,12 @@ Deluge.Statusbar = Ext.extend(Ext.ux.StatusBar, {
function addSpeed(val) {return val + ' KiB/s'} function addSpeed(val) {return val + ' KiB/s'}
var updateStat = function(name, config) { var updateStat = Ext.bind(function(name, config) {
var item = this.items.get('statusbar-' + name); var item = this.items.get('statusbar-' + name);
if (config.limit.value > 0) { if (config.limit.value > 0) {
var value = (config.value.formatter) ? config.value.formatter(config.value.value, true) : config.value.value; var value = (config.value.formatter) ? config.value.formatter(config.value.value, true) : config.value.value;
var limit = (config.limit.formatter) ? config.limit.formatter(config.limit.value, true) : config.limit.value; var limit = (config.limit.formatter) ? config.limit.formatter(config.limit.value, true) : config.limit.value;
var str = String.format(config.format, value, limit); var str = Ext.String.format(config.format, value, limit);
} else { } else {
var str = (config.value.formatter) ? config.value.formatter(config.value.value, true) : config.value.value; var str = (config.value.formatter) ? config.value.formatter(config.value.value, true) : config.value.value;
} }
@ -265,7 +261,7 @@ Deluge.Statusbar = Ext.extend(Ext.ux.StatusBar, {
if (!item.menu) return; if (!item.menu) return;
item.menu.setValue(config.limit.value); item.menu.setValue(config.limit.value);
}.createDelegate(this); }, this);
updateStat('connections', { updateStat('connections', {
value: {value: stats.num_connections}, value: {value: stats.num_connections},

View File

@ -40,7 +40,7 @@ Deluge.StatusbarMenu = Ext.extend(Ext.menu.Menu, {
initComponent: function() { initComponent: function() {
Deluge.StatusbarMenu.superclass.initComponent.call(this); Deluge.StatusbarMenu.superclass.initComponent.call(this);
this.otherWin = new Deluge.OtherLimitWindow(this.initialConfig.otherWin || {}); this.otherWin = Ext.create('Deluge.OtherLimitWindow', this.initialConfig.otherWin || {});
this.items.each(function(item) { this.items.each(function(item) {
if (item.getXType() != 'menucheckitem') return; if (item.getXType() != 'menucheckitem') return;

View File

@ -157,11 +157,7 @@ Deluge.Toolbar = Ext.extend(Ext.Toolbar, {
}, },
onTorrentAction: function(item) { onTorrentAction: function(item) {
var selection = deluge.torrents.getSelections(); var ids = deluge.torrents.getSelectedIds();
var ids = [];
Ext.each(selection, function(record) {
ids.push(record.id);
});
switch (item.id) { switch (item.id) {
case 'remove': case 'remove':

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.TorrentGrid.js * Deluge.TorrentGrid.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -30,45 +30,43 @@
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
(function() {
/* Renderers for the Torrent Grid */ /* Renderers for the Torrent Grid */
function queueRenderer(value) { function queueRenderer(value) {
return (value == -1) ? '' : value + 1; return (value == -1) ? '' : value + 1;
} }
function torrentNameRenderer(value, p, r) { function torrentNameRenderer(value, p, r) {
return String.format('<div class="torrent-name x-deluge-{0}">{1}</div>', r.data['state'].toLowerCase(), value); return Ext.String.format('<div class="torrent-name x-deluge-{0}">{1}</div>', r.data['state'].toLowerCase(), value);
} }
function torrentSpeedRenderer(value) { function torrentSpeedRenderer(value) {
if (!value) return; if (!value) return;
return fspeed(value); return fspeed(value);
} }
function torrentProgressRenderer(value, p, r) { function torrentProgressRenderer(value, md, r) {
value = new Number(value); value = Number(value);
var progress = value; var width = this.query('gridcolumn[dataIndex=progress]')[0].getWidth(),
var text = r.data['state'] + ' ' + value.toFixed(2) + '%'; progress = value,
var width = new Number(this.style.match(/\w+:\s*(\d+)\w+/)[1]); text = r.data['state'] + ' ' + value.toFixed(2) + '%';
return Deluge.progressBar(value, width - 8, text); return Deluge.progressBar(value, width - 8, text);
} }
function seedsRenderer(value, p, r) { function seedsRenderer(value, p, r) {
if (r.data['total_seeds'] > -1) { if (r.data['total_seeds'] > -1) {
return String.format('{0} ({1})', value, r.data['total_seeds']); return Ext.String.format('{0} ({1})', value, r.data['total_seeds']);
} else { } else {
return value; return value;
} }
} }
function peersRenderer(value, p, r) { function peersRenderer(value, p, r) {
if (r.data['total_peers'] > -1) { if (r.data['total_peers'] > -1) {
return String.format('{0} ({1})', value, r.data['total_peers']); return Ext.String.format('{0} ({1})', value, r.data['total_peers']);
} else { } else {
return value; return value;
} }
} }
function availRenderer(value, p, r) { function availRenderer(value, p, r) {
return (value < 0) ? '&infin;' : new Number(value).toFixed(3); return (value < 0) ? '&infin;' : Number(value).toFixed(3);
} }
function trackerRenderer(value, p, r) { function trackerRenderer(value, p, r) {
return String.format('<div style="background: url(' + deluge.config.base + 'tracker/{0}) no-repeat; padding-left: 20px;">{0}</div>', value); return Ext.String.format('<div style="background: url(' + deluge.config.base + 'tracker/{0}) no-repeat; padding-left: 20px;">{0}</div>', value);
} }
function etaSorter(eta) { function etaSorter(eta) {
@ -86,24 +84,24 @@
* @version 1.3 * @version 1.3
* *
* @class Deluge.TorrentGrid * @class Deluge.TorrentGrid
* @extends Ext.grid.GridPanel * @extends Ext.grid.Panel
* @constructor * @constructor
* @param {Object} config Configuration options * @param {Object} config Configuration options
*/ */
Deluge.TorrentGrid = Ext.extend(Ext.grid.GridPanel, { Ext.define('Deluge.TorrentGrid', {
extend: 'Ext.grid.Panel',
// object to store contained torrent ids // object to store contained torrent ids
torrents: {}, torrents: {},
columns: [{ columns: [{
id:'queue',
header: _('#'), header: _('#'),
width: 30, width: 30,
sortable: true, sortable: true,
renderer: queueRenderer, renderer: queueRenderer,
dataIndex: 'queue' dataIndex: 'queue'
}, { }, {
id:'name', flex: 1,
header: _('Name'), header: _('Name'),
width: 150, width: 150,
sortable: true, sortable: true,
@ -231,39 +229,58 @@
] ]
}, },
constructor: function(config) { store: Ext.create('Ext.data.Store', {
config = Ext.apply({ model: 'Deluge.data.Torrent',
proxy: {
type: 'memory',
reader: {
type: 'json',
root: 'torrents'
}
}
}),
viewConfig: {
stateId: 'torrentGridView',
stateful: true
},
id: 'torrentGrid', id: 'torrentGrid',
store: new Ext.data.JsonStore(this.meta),
columns: this.columns,
region: 'center', region: 'center',
cls: 'deluge-torrents', cls: 'deluge-torrents',
stripeRows: true, stripeRows: true,
autoExpandColumn: 'name',
deferredRender:false, deferredRender:false,
autoScroll:true, invalidateScrollOnRefresh: false,
margins: '5 5 0 0', margins: '5 5 0 0',
stateful: true,
view: new Ext.ux.grid.BufferView({
rowHeight: 26,
scrollDelay: false
})
}, config);
Deluge.TorrentGrid.superclass.constructor.call(this, config);
},
initComponent: function() { initComponent: function() {
Deluge.TorrentGrid.superclass.initComponent.call(this); this.callParent(arguments);
deluge.events.on('torrentRemoved', this.onTorrentRemoved, this); deluge.events.on('torrentRemoved', this.onTorrentRemoved, this);
deluge.events.on('disconnect', this.onDisconnect, this); deluge.events.on('disconnect', this.onDisconnect, this);
this.on('rowcontextmenu', function(grid, rowIndex, e) { this.on('itemcontextmenu', this.onTorrentSelected, this);
e.stopEvent();
var selection = grid.getSelectionModel(); this.on('staterestore', function(stateful, state, eopts) {
if (!selection.hasSelection()) { deluge.log('grid restoring state');
selection.selectRow(rowIndex); });
}
deluge.menus.torrent.showAt(e.getPoint()); this.on('selectionchange', function(grid, selected) {
if (selected.length)
deluge.details.update();
else
deluge.details.clear();
});
this.on('statesave', function() {
deluge.log('grid saving state');
});
this.getView().on('statesave', function() {
deluge.log('view saving state');
});
this.getView().on('staterestore', function(stateful, state, eopts) {
deluge.log('view restoring state');
}); });
}, },
@ -282,14 +299,14 @@
* @ return {Array/Ext.data.Record} The record(s) representing the rows * @ return {Array/Ext.data.Record} The record(s) representing the rows
*/ */
getSelected: function() { getSelected: function() {
return this.getSelectionModel().getSelected(); return this.getSelectionModel().getLastSelected();
}, },
/** /**
* Returns the currently selected records. * Returns the currently selected records.
*/ */
getSelections: function() { getSelections: function() {
return this.getSelectionModel().getSelections(); return this.getSelectionModel().getSelection();
}, },
/** /**
@ -297,7 +314,7 @@
* @return {String} The currently selected id. * @return {String} The currently selected id.
*/ */
getSelectedId: function() { getSelectedId: function() {
return this.getSelectionModel().getSelected().id return this.getSelected().getId()
}, },
/** /**
@ -306,8 +323,8 @@
*/ */
getSelectedIds: function() { getSelectedIds: function() {
var ids = []; var ids = [];
Ext.each(this.getSelectionModel().getSelections(), function(r) { Ext.each(this.getSelections(), function(r) {
ids.push(r.id); ids.push(r.getId());
}); });
return ids; return ids;
}, },
@ -336,9 +353,10 @@
} }
} }
record.endEdit(); record.endEdit();
record.commit();
} else { } else {
var record = new Deluge.data.Torrent(torrent); var record = Ext.create('Deluge.data.Torrent', torrent);
record.id = t; record.setId(t);
this.torrents[t] = 1; this.torrents[t] = 1;
newTorrents.push(record); newTorrents.push(record);
} }
@ -347,16 +365,15 @@
// Remove any torrents that should not be in the store. // Remove any torrents that should not be in the store.
store.each(function(record) { store.each(function(record) {
if (!torrents[record.id]) { if (!torrents[record.getId()]) {
store.remove(record); store.remove(record);
delete this.torrents[record.id]; delete this.torrents[record.getId()];
} }
}, this); }, this);
store.commitChanges(); store.sync();
var sortState = store.getSortState() // TODO: re-enable this is it's required.
if (!sortState) return; //store.sort(store.sorters);
store.sort(sortState.field, sortState.direction);
}, },
// private // private
@ -376,7 +393,15 @@
this.getStore().remove(record); this.getStore().remove(record);
delete this.torrents[torrentId]; delete this.torrents[torrentId];
}, this); }, this);
},
onTorrentSelected: function(grid, record, item, i, e, opts) {
e.stopEvent();
var sm = grid.getSelectionModel();
if (!sm.hasSelection()) {
sm.select(record);
}
var point = e.getPoint();
deluge.menus.torrent.showAt(point.x, point.y);
} }
}); });
deluge.torrents = new Deluge.TorrentGrid();
})();

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.UI.js * Deluge.UI.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -47,17 +47,21 @@ deluge.ui = {
* and set up various events that the UI will utilise. * and set up various events that the UI will utilise.
*/ */
initialize: function() { initialize: function() {
deluge.add = new Deluge.add.AddWindow();
deluge.details = new Deluge.details.DetailsPanel();
deluge.connectionManager = new Deluge.ConnectionManager();
deluge.editTrackers = new Deluge.EditTrackersWindow();
deluge.login = new Deluge.LoginWindow();
deluge.preferences = new Deluge.preferences.PreferencesWindow();
deluge.sidebar = new Deluge.Sidebar();
deluge.statusbar = new Deluge.Statusbar();
deluge.toolbar = new Deluge.Toolbar();
this.MainPanel = new Ext.Panel({ deluge.events = Ext.create('Deluge.EventsManager');
deluge.add = Ext.create('Deluge.add.AddWindow');
deluge.details = Ext.create('Deluge.details.DetailsPanel');
deluge.connectionManager = Ext.create('Deluge.ConnectionManager');
deluge.editTrackers = Ext.create('Deluge.EditTrackersWindow');
deluge.login = Ext.create('Deluge.LoginWindow');
deluge.preferences = Ext.create('Deluge.preferences.PreferencesWindow');
deluge.removeWindow = Ext.create('Deluge.RemoveWindow');
deluge.sidebar = Ext.create('Deluge.Sidebar');
deluge.statusbar = Ext.create('Deluge.StatusBar');
deluge.toolbar = Ext.create('Deluge.Toolbar');
deluge.torrents = Ext.create('Deluge.TorrentGrid');
this.MainPanel = Ext.create('Ext.Panel', {
id: 'mainPanel', id: 'mainPanel',
iconCls: 'x-deluge-main-panel', iconCls: 'x-deluge-main-panel',
title: 'Deluge', title: 'Deluge',
@ -71,7 +75,7 @@ deluge.ui = {
bbar: deluge.statusbar bbar: deluge.statusbar
}); });
this.Viewport = new Ext.Viewport({ this.Viewport = Ext.create('Ext.Viewport', {
layout: 'fit', layout: 'fit',
items: [this.MainPanel] items: [this.MainPanel]
}); });
@ -80,7 +84,7 @@ deluge.ui = {
deluge.events.on("disconnect", this.onDisconnect, this); deluge.events.on("disconnect", this.onDisconnect, this);
deluge.events.on('PluginDisabledEvent', this.onPluginDisabled, this); deluge.events.on('PluginDisabledEvent', this.onPluginDisabled, this);
deluge.events.on('PluginEnabledEvent', this.onPluginEnabled, this); deluge.events.on('PluginEnabledEvent', this.onPluginEnabled, this);
deluge.client = new Ext.ux.util.RpcClient({ deluge.client = Ext.create('Ext.ux.util.RpcClient', {
url: deluge.config.base + 'json' url: deluge.config.base + 'json'
}); });
@ -96,10 +100,12 @@ deluge.ui = {
deluge.client.on('connected', function(e) { deluge.client.on('connected', function(e) {
deluge.login.show(); deluge.login.show();
Ext.get('loading').remove();
Ext.get('loading-mask').fadeOut({remove:true});
}, this, {single: true}); }, this, {single: true});
this.update = this.update.createDelegate(this); this.update = Ext.bind(this.update, this);
this.checkConnection = this.checkConnection.createDelegate(this); this.checkConnection = Ext.bind(this.checkConnection, this);
this.originalTitle = document.title; this.originalTitle = document.title;
}, },

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.add.AddWindow.js * Deluge.add.AddWindow.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -30,9 +30,8 @@
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.namespace('Deluge.add'); Ext.define('Deluge.add.AddWindow', {
extend: 'Deluge.add.Window',
Deluge.add.AddWindow = Ext.extend(Deluge.add.Window, {
title: _('Add Torrents'), title: _('Add Torrents'),
layout: 'border', layout: 'border',
@ -46,52 +45,68 @@ Deluge.add.AddWindow = Ext.extend(Deluge.add.Window, {
iconCls: 'x-deluge-add-window-icon', iconCls: 'x-deluge-add-window-icon',
initComponent: function() { initComponent: function() {
Deluge.add.AddWindow.superclass.initComponent.call(this); this.callParent(arguments);
this.afterMethod('onHide', this.afterHidden, this);
this.afterMethod('onShow', this.afterShown, this);
this.addButton(_('Cancel'), this.onCancelClick, this); this.addDocked({
this.addButton(_('Add'), this.onAddClick, this); xtype: 'toolbar',
dock: 'bottom',
defaultType: 'button',
items: [
'->',
{text: _('Cancel'), handler: this.onCancelClick, scope: this},
{text: _('Add'), handler: this.onAddClick, scope: this}
]
});
function torrentRenderer(value, p, r) { function torrentRenderer(value, p, r) {
if (r.data['info_hash']) { if (r.data['info_hash']) {
return String.format('<div class="x-deluge-add-torrent-name">{0}</div>', value); return Ext.String.format('<div class="x-deluge-add-torrent-name">{0}</div>', value);
} else { } else {
return String.format('<div class="x-deluge-add-torrent-name-loading">{0}</div>', value); return Ext.String.format('<div class="x-deluge-add-torrent-name-loading">{0}</div>', value);
} }
} }
this.list = new Ext.list.ListView({ this.grid = this.add({
store: new Ext.data.SimpleStore({ xtype: 'grid',
fields: [ autoScroll: true,
{name: 'info_hash', mapping: 1}, store: Ext.create('Ext.data.Store', {
{name: 'text', mapping: 2} model: 'Deluge.data.AddTorrent'
],
id: 0
}), }),
columns: [{ columns: [{
id: 'torrent', id: 'torrent',
width: 150, width: 150,
sortable: true, sortable: true,
renderer: torrentRenderer, renderer: torrentRenderer,
dataIndex: 'text' dataIndex: 'text',
flex: 1
}], }],
stripeRows: true, hideHeaders: true,
margins: '5 5 5 5',
region: 'center',
singleSelect: true, singleSelect: true,
listeners: { listeners: {
'selectionchange': { 'selectionchange': {
fn: this.onSelect, fn: this.onSelect,
scope: this scope: this
},
'render': {
fn: function(list) {
var el = list.getEl(),
dh = Ext.core.DomHelper,
dropEl = {
tag: 'div',
cls: 'x-deluge-dropzone',
style: 'display: none',
html: 'Drop torrent file here'
};
this.dropEl = Ext.get(dh.insertFirst(el, dropEl));
},
scope: this
} }
}, },
hideHeaders: true, bbar: {
autoExpandColumn: 'torrent',
autoScroll: true
});
this.add({
region: 'center',
items: [this.list],
margins: '5 5 5 5',
bbar: new Ext.Toolbar({
items: [{ items: [{
iconCls: 'x-deluge-add-file', iconCls: 'x-deluge-add-file',
text: _('File'), text: _('File'),
@ -112,23 +127,25 @@ Deluge.add.AddWindow = Ext.extend(Deluge.add.Window, {
handler: this.onRemove, handler: this.onRemove,
scope: this scope: this
}] }]
}) }
}); });
this.optionsPanel = this.add(new Deluge.add.OptionsPanel()); this.optionsPanel = this.add(Ext.create('Deluge.add.OptionsPanel'));
this.on('hide', this.onHide, this);
this.on('show', this.onShow, this);
}, },
clear: function() { clear: function() {
this.list.getStore().removeAll(); this.grid.getStore().removeAll();
this.optionsPanel.clear(); this.optionsPanel.clear();
}, },
processDnDFileUpload: function(file) {
console.log(file.size);
},
onAddClick: function() { onAddClick: function() {
var torrents = []; var torrents = [];
if (!this.list) return; if (!this.grid) return;
this.list.getStore().each(function(r) { this.grid.getStore().each(function(r) {
var id = r.get('info_hash'); var id = r.get('info_hash');
torrents.push({ torrents.push({
path: this.optionsPanel.getFilename(id), path: this.optionsPanel.getFilename(id),
@ -150,28 +167,22 @@ Deluge.add.AddWindow = Ext.extend(Deluge.add.Window, {
}, },
onFile: function() { onFile: function() {
if (!this.file) this.file = new Deluge.add.FileWindow(); if (!this.file) this.file = Ext.create('Deluge.add.FileWindow');
this.file.show(); this.file.show();
}, },
onHide: function() {
this.optionsPanel.setActiveTab(0);
this.optionsPanel.files.setDisabled(true);
this.optionsPanel.form.setDisabled(true);
},
onRemove: function() { onRemove: function() {
if (!this.list.getSelectionCount()) return; if (!this.list.getSelectionCount()) return;
var torrent = this.list.getSelectedRecords()[0]; var torrent = this.grid.getSelectedRecords()[0];
this.list.getStore().remove(torrent); this.grid.getStore().remove(torrent);
this.optionsPanel.clear(); this.optionsPanel.clear();
if (this.torrents && this.torrents[torrent.id]) delete this.torrents[torrent.id]; if (this.torrents && this.torrents[torrent.id]) delete this.torrents[torrent.id];
}, },
onSelect: function(list, selections) { onSelect: function(grid, selections) {
if (selections.length) { if (selections.length) {
var record = this.list.getRecord(selections[0]); var record = selections[0];
this.optionsPanel.setTorrent(record.get('info_hash')); this.optionsPanel.setTorrent(record.get('info_hash'));
this.optionsPanel.files.setDisabled(false); this.optionsPanel.files.setDisabled(false);
this.optionsPanel.form.setDisabled(false); this.optionsPanel.form.setDisabled(false);
@ -181,29 +192,95 @@ Deluge.add.AddWindow = Ext.extend(Deluge.add.Window, {
} }
}, },
onShow: function() { afterHidden: function() {
this.optionsPanel.setActiveTab(0);
this.optionsPanel.files.setDisabled(true);
this.optionsPanel.form.setDisabled(true);
},
afterShown: function() {
if (!this.url) { if (!this.url) {
this.url = new Deluge.add.UrlWindow(); this.url = Ext.create('Deluge.add.UrlWindow');
this.url.on('beforeadd', this.onTorrentBeforeAdd, this); this.url.on('beforeadd', this.onTorrentBeforeAdd, this);
this.url.on('add', this.onTorrentAdd, this); this.url.on('add', this.onTorrentAdd, this);
} }
if (!this.file) { if (!this.file) {
this.file = new Deluge.add.FileWindow(); this.file = Ext.create('Deluge.add.FileWindow');
this.file.on('beforeadd', this.onTorrentBeforeAdd, this); this.file.on('beforeadd', this.onTorrentBeforeAdd, this);
this.file.on('add', this.onTorrentAdd, this); this.file.on('add', this.onTorrentAdd, this);
} }
this.optionsPanel.form.getDefaults(); this.optionsPanel.form.getDefaults();
var body = Ext.getBody(),
dropEl = this.dropEl;
body.on({
dragenter: function(evt) {
dropEl.setStyle('display', 'block');
return true;
},
dragleave: function(evt) {
var viewSize = body.getViewSize(),
pageX = evt.getPageX(),
pageY = evt.getPageY();
if (pageX < 10 || pageY < 10 || viewSize.width - pageX < 10 || viewSize.height - pageY < 10) {
dropEl.setStyle('display', 'none');
}
return true;
},
dragover: function(evt) {
evt.stopEvent();
return true;
},
drop: function(evt) {
evt.stopEvent();
return true;
}
});
this.dropEl.on({
dragenter: function(evt) {
evt.browserEvent.dataTransfer.dropEffect = 'move';
return true;
},
dragover: function(evt) {
evt.browserEvent.dataTransfer.dropEffect = 'move';
evt.stopEvent();
return true;
},
drop: {
fn: function(evt) {
evt.stopEvent();
var files = evt.browserEvent.dataTransfer.files;
if (files === undefined) {
return true;
}
var len = files.length;
while (--len >= 0) {
this.processDnDFileUpload(files[len]);
}
this.dropEl.setStyle('display', 'none');
},
scope: this
}
});
}, },
onTorrentBeforeAdd: function(torrentId, text) { onTorrentBeforeAdd: function(torrentId, text) {
var store = this.list.getStore(); var rec = Ext.create('Deluge.data.AddTorrent', {
store.loadData([[torrentId, null, text]], true); 'id': torrentId,
'info_hash': null,
'text': text
}, torrentId);
this.grid.getStore().add(rec);
}, },
onTorrentAdd: function(torrentId, info) { onTorrentAdd: function(torrentId, info) {
var r = this.list.getStore().getById(torrentId); var r = this.grid.getStore().getById(String(torrentId));
if (!info) { if (!info) {
Ext.MessageBox.show({ Ext.MessageBox.show({
title: _('Error'), title: _('Error'),
@ -213,11 +290,11 @@ Deluge.add.AddWindow = Ext.extend(Deluge.add.Window, {
icon: Ext.MessageBox.ERROR, icon: Ext.MessageBox.ERROR,
iconCls: 'x-deluge-icon-error' iconCls: 'x-deluge-icon-error'
}); });
this.list.getStore().remove(r); this.grid.getStore().remove(r);
} else { } else {
r.set('info_hash', info['info_hash']); r.set('info_hash', info['info_hash']);
r.set('text', info['name']); r.set('text', info['name']);
this.list.getStore().commitChanges(); r.commit();;
this.optionsPanel.addTorrent(info); this.optionsPanel.addTorrent(info);
} }
}, },

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.add.File.js * Deluge.add.File.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,13 +29,13 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.ns('Deluge.add');
/** /**
* @class Deluge.add.FileWindow * @class Deluge.add.FileWindow
* @extends Deluge.add.Window * @extends Deluge.add.Window
*/ */
Deluge.add.FileWindow = Ext.extend(Deluge.add.Window, { Ext.define('Deluge.add.FileWindow', {
extend: 'Deluge.add.Window',
title: _('Add from File'), title: _('Add from File'),
layout: 'fit', layout: 'fit',
@ -49,25 +49,32 @@ Deluge.add.FileWindow = Ext.extend(Deluge.add.Window, {
iconCls: 'x-deluge-add-file', iconCls: 'x-deluge-add-file',
initComponent: function() { initComponent: function() {
Deluge.add.FileWindow.superclass.initComponent.call(this); this.callParent(arguments);
this.addButton(_('Add'), this.onAddClick, this); this.addDocked({
xtype: 'toolbar',
dock: 'bottom',
defaultType: 'button',
items: [
'->',
{text: _('Add'), handler: this.onAddClick, scope: this}
]
});
this.form = this.add({ this.form = this.add({
xtype: 'form', xtype: 'form',
width: 300,
baseCls: 'x-plain', baseCls: 'x-plain',
labelWidth: 35,
autoHeight: true, autoHeight: true,
fileUpload: true,
items: [{ items: [{
xtype: 'fileuploadfield', xtype: 'filefield',
id: 'torrentFile', id: 'torrentFile',
width: 280, anchor: '100%',
emptyText: _('Select a torrent'), emptyText: _('Select a torrent'),
labelWidth: 35,
fieldLabel: _('File'), fieldLabel: _('File'),
name: 'file', name: 'file',
buttonCfg: { buttonText: _('Browse') + '...'
text: _('Browse') + '...'
}
}] }]
}); });
}, },

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.add.FilesTab.js * Deluge.add.FilesTab.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,13 +29,13 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.ns('Deluge.add');
/** /**
* @class Deluge.add.FilesTab * @class Deluge.add.FilesTab
* @extends Ext.ux.tree.TreeGrid * @extends Ext.ux.tree.TreeGrid
*/ */
Deluge.add.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, { Ext.define('Deluge.add.FilesTab', {
extend: 'Ext.tree.Panel',
layout: 'fit', layout: 'fit',
title: _('Files'), title: _('Files'),
@ -47,41 +47,46 @@ Deluge.add.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
rootVisible: false, rootVisible: false,
columns: [{ columns: [{
xtype: 'treecolumn',
header: _('Filename'), header: _('Filename'),
width: 295, width: 295,
dataIndex: 'filename' dataIndex: 'filename'
},{ },{
xtype: 'templatecolumn',
header: _('Size'), header: _('Size'),
width: 60, width: 60,
dataIndex: 'size', dataIndex: 'size',
tpl: new Ext.XTemplate('{size:this.fsize}', { tpl: Ext.create('Ext.XTemplate', '{size:this.fsize}', {
fsize: function(v) { fsize: function(v) {
return fsize(v); return fsize(v);
} }
}) })
},{ },{
xtype: 'templatecolumn',
header: _('Download'), header: _('Download'),
width: 65, width: 65,
dataIndex: 'download', dataIndex: 'download',
tpl: new Ext.XTemplate('{download:this.format}', { tpl: Ext.create('Ext.XTemplate', '{download:this.format}', {
format: function(v) { format: function(v) {
return '<div rel="chkbox" class="x-grid3-check-col'+(v?'-on':'')+'"> </div>'; return '<div rel="chkbox" class="x-grid3-check-col'+(v?'-on':'')+'"> </div>';
} }
}) })
}], }],
store: Ext.create('Ext.data.TreeStore', {
model: 'Deluge.data.AddTorrentFile',
proxy: {
type: 'memory'
}
}),
initComponent: function() { initComponent: function() {
Deluge.add.FilesTab.superclass.initComponent.call(this); this.callParent(arguments);
this.on('click', this.onNodeClick, this); this.on('click', this.onNodeClick, this);
}, },
clearFiles: function() { clearFiles: function() {
var root = this.getRootNode(); this.getStore().removeAll();
if (!root.hasChildNodes()) return;
root.cascade(function(node) {
if (!node.parentNode || !node.getOwnerTree()) return;
node.remove();
});
}, },
setDownload: function(node, value, suppress) { setDownload: function(node, value, suppress) {
@ -106,7 +111,7 @@ Deluge.add.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
}, },
onNodeClick: function(node, e) { onNodeClick: function(node, e) {
var el = new Ext.Element(e.target); var el = Ext.fly(e.target);
if (el.getAttribute('rel') == 'chkbox') { if (el.getAttribute('rel') == 'chkbox') {
this.setDownload(node, !node.attributes.download); this.setDownload(node, !node.attributes.download);
} }

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.add.Infohash.js * Deluge.add.Infohash.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,4 +29,3 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.namespace('Ext.deluge.add');

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.add.OptionsPanel.js * Deluge.add.OptionsPanel.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,9 +29,9 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.ns('Deluge.add');
Deluge.add.OptionsPanel = Ext.extend(Ext.TabPanel, { Ext.define('Deluge.add.OptionsPanel', {
extend: 'Ext.TabPanel',
torrents: {}, torrents: {},
@ -42,9 +42,9 @@ Deluge.add.OptionsPanel = Ext.extend(Ext.TabPanel, {
height: 220, height: 220,
initComponent: function() { initComponent: function() {
Deluge.add.OptionsPanel.superclass.initComponent.call(this); this.callParent(arguments);
this.files = this.add(new Deluge.add.FilesTab()); this.files = this.add(Ext.create('Deluge.add.FilesTab'));
this.form = this.add(new Deluge.add.OptionsTab()); this.form = this.add(Ext.create('Deluge.add.OptionsTab'));
this.files.on('fileschecked', this.onFilesChecked, this); this.files.on('fileschecked', this.onFilesChecked, this);
}, },

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.add.OptionsPanel.js * Deluge.add.OptionsPanel.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,13 +29,13 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.ns('Deluge.add');
/** /**
* @class Deluge.add.OptionsTab * @class Deluge.add.OptionsTab
* @extends Ext.form.FormPanel * @extends Ext.form.FormPanel
*/ */
Deluge.add.OptionsTab = Ext.extend(Ext.form.FormPanel, { Ext.define('Deluge.add.OptionsTab', {
extend: 'Ext.form.Panel',
title: _('Options'), title: _('Options'),
height: 170, height: 170,
@ -46,7 +46,7 @@ Deluge.add.OptionsTab = Ext.extend(Ext.form.FormPanel, {
labelWidth: 1, labelWidth: 1,
initComponent: function() { initComponent: function() {
Deluge.add.OptionsTab.superclass.initComponent.call(this); this.callParent(arguments);
this.optionsManager = new Deluge.MultiOptionsManager(); this.optionsManager = new Deluge.MultiOptionsManager();

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.add.UrlWindow.js * Deluge.add.UrlWindow.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -30,15 +30,15 @@
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.namespace('Deluge.add'); Ext.define('Deluge.add.UrlWindow', {
Deluge.add.UrlWindow = Ext.extend(Deluge.add.Window, { extend: 'Deluge.add.Window',
title: _('Add from Url'), title: _('Add from Url'),
modal: true, modal: true,
plain: true, plain: true,
layout: 'fit', layout: 'fit',
width: 350, width: 350,
height: 155, height: 130,
buttonAlign: 'center', buttonAlign: 'center',
closeAction: 'hide', closeAction: 'hide',
@ -46,29 +46,39 @@ Deluge.add.UrlWindow = Ext.extend(Deluge.add.Window, {
iconCls: 'x-deluge-add-url-window-icon', iconCls: 'x-deluge-add-url-window-icon',
initComponent: function() { initComponent: function() {
Deluge.add.UrlWindow.superclass.initComponent.call(this); this.callParent(arguments);
this.addButton(_('Add'), this.onAddClick, this);
this.addDocked({
xtype: 'toolbar',
dock: 'bottom',
defaultType: 'button',
items: [
'->',
{text: _('Add'), handler: this.onAddClick, scope: this}
]
});
var form = this.add({ var form = this.add({
xtype: 'form', xtype: 'form',
defaultType: 'textfield', defaultType: 'textfield',
baseCls: 'x-plain', baseCls: 'x-plain',
labelWidth: 55 defaults: {
labelWidth: 55,
anchor: '100%'
}
}); });
this.urlField = form.add({ this.urlField = form.add({
fieldLabel: _('Url'), fieldLabel: _('Url'),
id: 'url', id: 'url',
name: 'url', name: 'url'
width: '97%'
}); });
this.urlField.on('specialkey', this.onAdd, this); this.urlField.on('specialkey', this.onAdd, this);
this.cookieField = form.add({ this.cookieField = form.add({
fieldLabel: _('Cookies'), fieldLabel: _('Cookies'),
id: 'cookies', id: 'cookies',
name: 'cookies', name: 'cookies'
width: '97%'
}); });
this.cookieField.on('specialkey', this.onAdd, this); this.cookieField.on('specialkey', this.onAdd, this);
}, },

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.add.Window.js * Deluge.add.Window.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,16 +29,17 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.ns('Deluge.add');
/** /**
* @class Deluge.add.Window * @class Deluge.add.Window
* @extends Ext.Window * @extends Ext.Window
* Base class for an add Window * Base class for an add Window
*/ */
Deluge.add.Window = Ext.extend(Ext.Window, { Ext.define('Deluge.add.Window', {
extend: 'Ext.Window',
initComponent: function() { initComponent: function() {
Deluge.add.Window.superclass.initComponent.call(this); this.callParent(arguments);
this.addEvents( this.addEvents(
'beforeadd', 'beforeadd',
'add' 'add'

View File

@ -1,7 +1,7 @@
/*! /*!
* Ext.ux.tree.TreeGridNodeUIFix.js * Deluge.data.AddTorrent.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -30,24 +30,11 @@
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.override(Ext.ux.tree.TreeGridNodeUI, { Ext.define('Deluge.data.AddTorrent', {
extend: 'Ext.data.Model',
updateColumns: function() { fields: [
if (!this.rendered) return; {name: 'id', type: 'string'},
{name: 'info_hash', type: 'string'},
var a = this.node.attributes, {name: 'text', type: 'string'}
t = this.node.getOwnerTree(), ]
cols = t.columns,
c = cols[0];
// Update the first column
this.anchor.firstChild.innerHTML = (c.tpl ? c.tpl.apply(a) : a[c.dataIndex] || c.text);
// Update the remaining columns
for(i = 1, len = cols.length; i < len; i++) {
c = cols[i];
this.elNode.childNodes[i].firstChild.innerHTML = (c.tpl ? c.tpl.apply(a) : a[c.dataIndex] || c.text);
}
}
}); });

View File

@ -1,7 +1,7 @@
/*! /*!
* Ext.ux.form.RadioGroup.js * Deluge.data.AddTorrentFile.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -30,42 +30,11 @@
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
// Allow radiogroups to be treated as a single form element. Ext.define('Deluge.data.AddTorrentFile', {
Ext.override(Ext.form.RadioGroup, { extend: 'Ext.data.Model',
fields: [
afterRender: function() { {name: 'filename', type: 'string'},
this.items.each(function(i) { {name: 'size', type: 'number'},
this.relayEvents(i, ['check']); {name: 'download', type: 'boolean'}
}, this); ]
if (this.lazyValue) {
this.setValue(this.value);
delete this.value;
delete this.lazyValue;
}
Ext.form.RadioGroup.superclass.afterRender.call(this)
},
getName: function() {
return this.items.first().getName();
},
getValue: function() {
return this.items.first().getGroupValue();
},
setValue: function(v) {
if (!this.items.each) {
this.value = v;
this.lazyValue = true;
return;
}
this.items.each(function(item) {
if (item.rendered) {
var checked = (item.el.getValue() == String(v));
item.el.dom.checked = checked;
item.el.dom.defaultChecked = checked;
item.wrap[checked ? 'addClass' : 'removeClass'](item.checkedCls);
}
});
}
}); });

View File

@ -0,0 +1,50 @@
/*!
* Deluge.data.FilterRecord.js
*
* Copyright (c) Damien Churchill 2011 <damoxc@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, write to:
* The Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the OpenSSL
* library.
* You must obey the GNU General Public License in all respects for all of
* the code used other than OpenSSL. If you modify file(s) with this
* exception, you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete
* this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here.
*/
/**
* Deluge.data.Filter record
*
* @author Damien Churchill <damoxc@gmail.com>
* @version 1.4
*
* @class Deluge.data.Filter
* @extends Ext.data.Model
* @constructor
* @param {Object} data The Filter data
*/
Ext.define('Deluge.data.Filter', {
extend: 'Ext.data.Model',
fields: [
{name: 'filter', type: 'string'},
{name: 'count', type: 'number'}
]
});

View File

@ -0,0 +1,53 @@
/*!
* Deluge.data.Host.js
*
* Copyright (c) Damien Churchill 2011 <damoxc@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, write to:
* The Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the OpenSSL
* library.
* You must obey the GNU General Public License in all respects for all of
* the code used other than OpenSSL. If you modify file(s) with this
* exception, you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete
* this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here.
*/
/**
* Deluge.data.Host
*
* @author Damien Churchill <damoxc@gmail.com>
* @version 1.4
*
* @class Deluge.data.Host
* @extends Ext.data.Model
* @constructor
* @param {Object} data The peer data
*/
Ext.define('Deluge.data.Host', {
extend: 'Ext.data.Model',
fields: [
{name: 'id', type: 'string'},
{name: 'host', type: 'string'},
{name: 'port', type: 'int'},
{name: 'status', type: 'string'},
{name: 'version', type: 'string'}
]
});

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.data.PeerRecord.js * Deluge.data.Peer.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,7 +29,6 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.namespace('Deluge.data');
/** /**
* Deluge.data.Peer record * Deluge.data.Peer record
@ -38,32 +37,19 @@ Ext.namespace('Deluge.data');
* @version 1.3 * @version 1.3
* *
* @class Deluge.data.Peer * @class Deluge.data.Peer
* @extends Ext.data.Record * @extends Ext.data.Model
* @constructor * @constructor
* @param {Object} data The peer data * @param {Object} data The peer data
*/ */
Deluge.data.Peer = Ext.data.Record.create([ Ext.define('Deluge.data.Peer', {
{ extend: 'Ext.data.Model',
name: 'country', fields: [
type: 'string' {name: 'country', type: 'string'},
}, { {name: 'ip', type: 'string', sortType: Deluge.data.SortTypes.asIPAddress},
name: 'ip', {name: 'client', type: 'string'},
type: 'string', {name: 'progress', type: 'float'},
sortType: Deluge.data.SortTypes.asIPAddress {name: 'down_speed', type: 'int'},
}, { {name: 'up_speed', type: 'int'},
name: 'client', {name: 'seed', type: 'int'}
type: 'string' ]
}, { });
name: 'progress',
type: 'float'
}, {
name: 'down_speed',
type: 'int'
}, {
name: 'up_speed',
type: 'int'
}, {
name: 'seed',
type: 'int'
}
]);

View File

@ -0,0 +1,50 @@
/*!
* Deluge.data.Plugin.js
*
* Copyright (c) Damien Churchill 2011 <damoxc@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, write to:
* The Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the OpenSSL
* library.
* You must obey the GNU General Public License in all respects for all of
* the code used other than OpenSSL. If you modify file(s) with this
* exception, you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete
* this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here.
*/
/**
* Deluge.data.Plugin record
*
* @author Damien Churchill <damoxc@gmail.com>
* @version 1.4
*
* @class Deluge.data.Plugin
* @extends Ext.data.Model
* @constructor
* @param {Object} data The plugin data
*/
Ext.define('Deluge.data.Plugin', {
extend: 'Ext.data.Model',
fields: [
{name: 'enabled', type: 'boolean'},
{name: 'plugin', type: 'string'}
]
});

View File

@ -1,7 +1,7 @@
/*! /*!
* Ext.ux.form.SpinnerField.js * Deluge.data.Preference.js
* *
* Copyright (c) Damien Churchill 2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -30,6 +30,9 @@
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.override(Ext.ux.form.SpinnerField, { Ext.define('Deluge.data.Preferences', {
onBlur: Ext.form.Field.prototype.onBlur extend: 'Ext.data.Model',
fields: [
{name: 'name', type: 'string'}
]
}); });

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.data.SortTypes.js * Deluge.data.SortTypes.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.data.TorrentRecord.js * Deluge.data.TorrentRecord.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,7 +29,6 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.namespace('Deluge.data');
/** /**
* Deluge.data.Torrent record * Deluge.data.Torrent record
@ -38,57 +37,28 @@ Ext.namespace('Deluge.data');
* @version 1.3 * @version 1.3
* *
* @class Deluge.data.Torrent * @class Deluge.data.Torrent
* @extends Ext.data.Record * @extends Ext.data.Model
* @constructor * @constructor
* @param {Object} data The torrents data * @param {Object} data The torrents data
*/ */
Deluge.data.Torrent = Ext.data.Record.create([{ Ext.define('Deluge.data.Torrent', {
name: 'queue', extend: 'Ext.data.Model',
type: 'int' fields: [
}, { {name: 'queue', type: 'int', sortType: Deluge.data.SortTypes.asQueuePosition},
name: 'name', {name: 'name', type: 'string'},
type: 'string' {name: 'total_size', type: 'int'},
}, { {name: 'state', type: 'string'},
name: 'total_size', {name: 'progress', type: 'float'},
type: 'int' {name: 'num_seeds', type: 'int'},
}, { {name: 'total_seeds', type: 'int'},
name: 'state', {name: 'num_peers', type: 'int'},
type: 'string' {name: 'total_peers', type: 'int'},
}, { {name: 'download_payload_rate', type: 'int'},
name: 'progress', {name: 'upload_payload_rate', type: 'int'},
type: 'int' {name: 'eta', type: 'int'},
}, { {name: 'ratio', type: 'float'},
name: 'num_seeds', {name: 'distributed_copies', type: 'float'},
type: 'int' {name: 'time_added', type: 'int'},
}, { {name: 'tracker_host', type: 'string'}
name: 'total_seeds', ]
type: 'int' });
}, {
name: 'num_peers',
type: 'int'
}, {
name: 'total_peers',
type: 'int'
}, {
name: 'download_payload_rate',
type: 'int'
}, {
name: 'upload_payload_rate',
type: 'int'
}, {
name: 'eta',
type: 'int'
}, {
name: 'ratio',
type: 'float'
}, {
name: 'distributed_copies',
type: 'float'
}, {
name: 'time_added',
type: 'int'
}, {
name: 'tracker_host',
type: 'string'
}
]);

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.details.DetailsPanel.js * Deluge.details.DetailsPanel.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,12 +29,12 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.namespace('Deluge.details');
/** /**
* @class Deluge.details.DetailsPanel * @class Deluge.details.DetailsPanel
*/ */
Deluge.details.DetailsPanel = Ext.extend(Ext.TabPanel, { Ext.define('Deluge.details.DetailsPanel', {
extend: 'Ext.tab.Panel',
region: 'south', region: 'south',
id: 'torrentDetails', id: 'torrentDetails',
@ -43,21 +43,21 @@ Deluge.details.DetailsPanel = Ext.extend(Ext.TabPanel, {
minSize: 100, minSize: 100,
collapsible: true, collapsible: true,
margins: '0 5 5 5', margins: '0 5 5 5',
activeTab: 0,
initComponent: function() { initComponent: function() {
Deluge.details.DetailsPanel.superclass.initComponent.call(this); this.callParent(arguments);
this.add(new Deluge.details.StatusTab()); this.add(Ext.create('Deluge.details.StatusTab'));
this.add(new Deluge.details.DetailsTab()); this.add(Ext.create('Deluge.details.DetailsTab'));
this.add(new Deluge.details.FilesTab()); this.add(Ext.create('Deluge.details.FilesTab'));
this.add(new Deluge.details.PeersTab()); this.add(Ext.create('Deluge.details.PeersTab'));
this.add(new Deluge.details.OptionsTab()); this.add(Ext.create('Deluge.details.OptionsTab'));
this.setActiveTab(0);
}, },
clear: function() { clear: function() {
this.items.each(function(panel) { this.items.each(function(panel) {
if (panel.clear) { if (panel.clear) {
panel.clear.defer(100, panel); Ext.defer(panel.clear, 100, panel);
panel.disable(); panel.disable();
} }
}); });
@ -76,7 +76,7 @@ Deluge.details.DetailsPanel = Ext.extend(Ext.TabPanel, {
}); });
tab = tab || this.getActiveTab(); tab = tab || this.getActiveTab();
if (tab.update) tab.update(torrent.id); if (tab.update) tab.update(torrent.getId());
}, },
/* Event Handlers */ /* Event Handlers */
@ -84,7 +84,7 @@ Deluge.details.DetailsPanel = Ext.extend(Ext.TabPanel, {
// We need to add the events in onRender since Deluge.Torrents hasn't // We need to add the events in onRender since Deluge.Torrents hasn't
// been created yet. // been created yet.
onRender: function(ct, position) { onRender: function(ct, position) {
Deluge.details.DetailsPanel.superclass.onRender.call(this, ct, position); this.callParent(arguments);
deluge.events.on('disconnect', this.clear, this); deluge.events.on('disconnect', this.clear, this);
deluge.torrents.on('rowclick', this.onTorrentsClick, this); deluge.torrents.on('rowclick', this.onTorrentsClick, this);
this.on('tabchange', this.onTabChange, this); this.on('tabchange', this.onTabChange, this);

View File

@ -1,48 +1,47 @@
/* /*!
Script: Deluge.Details.Details.js * Deluge.details.DetailsTab.js
The details tab displayed in the details panel. *
* Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
Copyright: *
(C) Damien Churchill 2009-2010 <damoxc@gmail.com> *
This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option) * the Free Software Foundation; either version 3, or (at your option)
any later version. * any later version.
*
This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. * GNU General Public License for more details.
*
You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
along with this program. If not, write to: * along with this program. If not, write to:
The Free Software Foundation, Inc., * The Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
Boston, MA 02110-1301, USA. * Boston, MA 02110-1301, USA.
*
In addition, as a special exception, the copyright holders give * In addition, as a special exception, the copyright holders give
permission to link the code of portions of this program with the OpenSSL * permission to link the code of portions of this program with the OpenSSL
library. * library.
You must obey the GNU General Public License in all respects for all of * You must obey the GNU General Public License in all respects for all of
the code used other than OpenSSL. If you modify file(s) with this * the code used other than OpenSSL. If you modify file(s) with this
exception, you may extend this exception to your version of the file(s), * exception, you may extend this exception to your version of the file(s),
but you are not obligated to do so. If you do not wish to do so, delete * but you are not obligated to do so. If you do not wish to do so, delete
this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Deluge.details.DetailsTab = Ext.extend(Ext.Panel, { Ext.define('Deluge.details.DetailsTab', {
extend: 'Ext.Panel',
title: _('Details'), title: _('Details'),
autoScroll: true,
fields: {}, fields: {},
queuedItems: {}, queuedItems: {},
oldData: {}, oldData: {},
initComponent: function() { initComponent: function() {
Deluge.details.DetailsTab.superclass.initComponent.call(this); this.callParent(arguments);
this.addItem('torrent_name', _('Name')); this.addItem('torrent_name', _('Name'));
this.addItem('hash', _('Hash')); this.addItem('hash', _('Hash'));
this.addItem('path', _('Path')); this.addItem('path', _('Path'));
@ -51,12 +50,14 @@ Deluge.details.DetailsTab = Ext.extend(Ext.Panel, {
this.addItem('comment', _('Comment')); this.addItem('comment', _('Comment'));
this.addItem('status', _('Status')); this.addItem('status', _('Status'));
this.addItem('tracker', _('Tracker')); this.addItem('tracker', _('Tracker'));
this.addItem('owner', _('Owner'));
this.addItem('shared', _('Shared'));
}, },
onRender: function(ct, position) { onRender: function(ct, position) {
Deluge.details.DetailsTab.superclass.onRender.call(this, ct, position); this.callParent(arguments);
this.body.setStyle('padding', '10px'); this.body.setStyle('padding', '10px');
this.dl = Ext.DomHelper.append(this.body, {tag: 'dl'}, true); this.dl = Ext.core.DomHelper.append(this.body, {tag: 'dl'}, true);
for (var id in this.queuedItems) { for (var id in this.queuedItems) {
this.doAddItem(id, this.queuedItems[id]); this.doAddItem(id, this.queuedItems[id]);
@ -73,8 +74,8 @@ Deluge.details.DetailsTab = Ext.extend(Ext.Panel, {
// private // private
doAddItem: function(id, label) { doAddItem: function(id, label) {
Ext.DomHelper.append(this.dl, {tag: 'dt', cls: id, html: label + ':'}); Ext.core.DomHelper.append(this.dl, {tag: 'dt', cls: id, html: label + ':'});
this.fields[id] = Ext.DomHelper.append(this.dl, {tag: 'dd', cls: id, html: ''}, true); this.fields[id] = Ext.core.DomHelper.append(this.dl, {tag: 'dd', cls: id, html: ''}, true);
}, },
clear: function() { clear: function() {
@ -102,11 +103,14 @@ Deluge.details.DetailsTab = Ext.extend(Ext.Panel, {
files: torrent.num_files, files: torrent.num_files,
status: torrent.message, status: torrent.message,
tracker: torrent.tracker, tracker: torrent.tracker,
comment: torrent.comment comment: torrent.comment,
owner: torrent.owner,
shared: torrent.shared
}; };
for (var field in this.fields) { for (var field in this.fields) {
if (!Ext.isDefined(data[field])) continue; // this is a field we aren't responsible for. // this is a field we aren't responsible for.
if (!Ext.isDefined(data[field])) continue;
if (data[field] == this.oldData[field]) continue; if (data[field] == this.oldData[field]) continue;
this.fields[field].dom.innerHTML = Ext.escapeHTML(data[field]); this.fields[field].dom.innerHTML = Ext.escapeHTML(data[field]);
} }

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.details.FilesTab.js * Deluge.details.FilesTab.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -30,38 +30,51 @@
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, { Ext.define('Deluge.data.File', {
extend: 'Ext.data.Model',
fields: [
{name: 'filename', type: 'string'},
{name: 'size', type: 'int'},
{name: 'progress', type: 'float'}
]
});
Ext.define('Deluge.details.FilesTab', {
extend: 'Ext.tree.Panel',
title: _('Files'), title: _('Files'),
autoScroll: true,
rootVisible: false,
columns: [{ columns: [{
header: _('Filename'), xtype: 'treecolumn',
text: _('Filename'),
width: 330, width: 330,
dataIndex: 'filename' dataIndex: 'filename'
}, { }, {
header: _('Size'), xtype: 'templatecolumn',
text: _('Size'),
width: 150, width: 150,
dataIndex: 'size', dataIndex: 'size',
tpl: new Ext.XTemplate('{size:this.fsize}', { tpl: Ext.create('Ext.XTemplate', '{size:this.fsize}', {
fsize: function(v) { return fsize(v); } fsize: function(v) { return fsize(v); }
}) })
}, { }, {
xtype: 'tgrendercolumn', xtype: 'templatecolumn',
header: _('Progress'), text: _('Progress'),
width: 150, width: 150,
dataIndex: 'progress', dataIndex: 'progress',
renderer: function(v) { tpl: Ext.create('Ext.XTemplate', '{progress:this.progress}', {
progress: function(v) {
var progress = v * 100; var progress = v * 100;
return Deluge.progressBar(progress, this.col.width, progress.toFixed(2) + '%', 0); return Deluge.progressBar(progress, this.col.width, progress.toFixed(2) + '%', 0);
} }
})
}, { }, {
header: _('Priority'), xtype: 'templatecolumn',
text: _('Priority'),
width: 150, width: 150,
dataIndex: 'priority', dataIndex: 'priority',
tpl: new Ext.XTemplate('<tpl if="!isNaN(priority)">' + tpl: Ext.create('Ext.XTemplate', '<tpl if="!isNaN(priority)">' +
'<div class="{priority:this.getClass}">' + '<div class="{priority:this.getClass}">' +
'{priority:this.getName}' + '{priority:this.getName}' +
'</div></tpl>', { '</div></tpl>', {
@ -75,93 +88,45 @@ Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
}) })
}], }],
selModel: new Ext.tree.MultiSelectionModel(), store: Ext.create('Ext.data.TreeStore', {
model: 'Deluge.data.File',
proxy: {
type: 'memory'
}
}),
initComponent: function() { autoScroll: true,
Deluge.details.FilesTab.superclass.initComponent.call(this); multiSelect: true,
this.setRootNode(new Ext.tree.TreeNode({text: 'Files'})); rootVisible: false,
}, useArrows: true,
clear: function() { clear: function() {
var root = this.getRootNode(); this.getStore().removeAll();
if (!root.hasChildNodes()) return;
root.cascade(function(node) {
var parentNode = node.parentNode;
if (!parentNode) return;
if (!parentNode.ownerTree) return;
parentNode.removeChild(node);
});
},
createFileTree: function(files) {
function walk(files, parentNode) {
for (var file in files.contents) {
var item = files.contents[file];
if (item.type == 'dir') {
walk(item, parentNode.appendChild(new Ext.tree.TreeNode({
text: file,
filename: file,
size: item.size,
progress: item.progress,
priority: item.priority
})));
} else {
parentNode.appendChild(new Ext.tree.TreeNode({
text: file,
filename: file,
fileIndex: item.index,
size: item.size,
progress: item.progress,
priority: item.priority,
leaf: true,
iconCls: 'x-deluge-file',
uiProvider: Ext.ux.tree.TreeGridNodeUI
}));
}
}
}
var root = this.getRootNode();
walk(files, root);
root.firstChild.expand();
}, },
update: function(torrentId) { update: function(torrentId) {
var store = this.getStore(),
view = this.getView();
if (this.torrentId != torrentId) { if (this.torrentId != torrentId) {
this.clear(); //store.removeAll();
store.setProxy({
type: 'ajax',
url: 'files/' + torrentId
})
this.torrentId = torrentId; this.torrentId = torrentId;
} }
deluge.client.web.get_torrent_files(torrentId, { store.load();
success: this.onRequestComplete,
scope: this,
torrentId: torrentId
});
},
updateFileTree: function(files) {
function walk(files, parentNode) {
for (var file in files.contents) {
var item = files.contents[file];
var node = parentNode.findChild('filename', file);
node.attributes.size = item.size;
node.attributes.progress = item.progress;
node.attributes.priority = item.priority;
node.ui.updateColumns();
if (item.type == 'dir') {
walk(item, node);
}
}
}
walk(files, this.getRootNode());
}, },
onRender: function(ct, position) { onRender: function(ct, position) {
Deluge.details.FilesTab.superclass.onRender.call(this, ct, position); Deluge.details.FilesTab.superclass.onRender.call(this, ct, position);
deluge.menus.filePriorities.on('itemclick', this.onItemClick, this); deluge.menus.filePriorities.on('itemclick', this.onItemClick, this);
this.on('contextmenu', this.onContextMenu, this); this.on('contextmenu', this.onContextMenu, this);
this.sorter = new Ext.tree.TreeSorter(this, { //this.sorter = new Ext.tree.TreeSorter(this, {
folderSort: true // folderSort: true
}); //});
}, },
onContextMenu: function(node, e) { onContextMenu: function(node, e) {
@ -216,13 +181,5 @@ Deluge.details.FilesTab = Ext.extend(Ext.ux.tree.TreeGrid, {
}); });
break; break;
} }
},
onRequestComplete: function(files, options) {
if (!this.getRootNode().hasChildNodes()) {
this.createFileTree(files);
} else {
this.updateFileTree(files);
}
} }
}); });

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.details.OptionsTab.js * Deluge.details.OptionsTab.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -30,11 +30,10 @@
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.define('Deluge.details.OptionsTab', {
extend: 'Ext.form.Panel',
Deluge.details.OptionsTab = Ext.extend(Ext.form.FormPanel, { title: _('Options'),
constructor: function(config) {
config = Ext.apply({
autoScroll: true, autoScroll: true,
bodyStyle: 'padding: 5px;', bodyStyle: 'padding: 5px;',
border: false, border: false,
@ -46,16 +45,12 @@ Deluge.details.OptionsTab = Ext.extend(Ext.form.FormPanel, {
}, },
deferredRender: false, deferredRender: false,
layout: 'column', layout: 'column',
title: _('Options')
}, config);
Deluge.details.OptionsTab.superclass.constructor.call(this, config);
},
initComponent: function() { initComponent: function() {
Deluge.details.OptionsTab.superclass.initComponent.call(this); this.callParent(arguments);
this.fieldsets = {}, this.fields = {}; this.fieldsets = {}, this.fields = {};
this.optionsManager = new Deluge.MultiOptionsManager({ this.optionsManager = Ext.create('Deluge.MultiOptionsManager', {
options: { options: {
'max_download_speed': -1, 'max_download_speed': -1,
'max_upload_speed': -1, 'max_upload_speed': -1,
@ -291,7 +286,7 @@ Deluge.details.OptionsTab = Ext.extend(Ext.form.FormPanel, {
autoHeight: true, autoHeight: true,
defaultType: 'checkbox', defaultType: 'checkbox',
title: _('General'), title: _('General'),
layout: 'form' layout: 'anchor'
}); });
this.fields['private'] = this.fieldsets.general.add({ this.fields['private'] = this.fieldsets.general.add({
@ -354,12 +349,12 @@ Deluge.details.OptionsTab = Ext.extend(Ext.form.FormPanel, {
}, },
onRender: function(ct, position) { onRender: function(ct, position) {
Deluge.details.OptionsTab.superclass.onRender.call(this, ct, position); this.callParent(arguments);
// This is another hack I think, so keep an eye out here when upgrading. // This is another hack I think, so keep an eye out here when upgrading.
this.layout = new Ext.layout.ColumnLayout(); //this.layout = new Ext.layout.ColumnLayout();
this.layout.setContainer(this); //this.layout.setContainer(this);
this.doLayout(); //this.doLayout();
}, },
clear: function() { clear: function() {

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.details.PeersTab.js * Deluge.details.PeersTab.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -30,136 +30,95 @@
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
(function() { Ext.define('Deluge.details.PeersTab', {
function flagRenderer(value) { extend: 'Ext.grid.Panel',
if (!value.replace(' ', '').replace(' ', '')){ id: 'peersGrid',
return '';
}
return String.format('<img src="flag/{0}" />', value);
}
function peerAddressRenderer(value, p, record) {
var seed = (record.data['seed'] == 1024) ? 'x-deluge-seed' : 'x-deluge-peer';
if (peer_ip.length > 2) {
var port = peer_ip.pop();
var ip = peer_ip.join(":");
value = "[" + ip + "]:" + port;
}
return String.format('<div class="{0}">{1}</div>', seed, value);
}
function peerProgressRenderer(value) {
var progress = (value * 100).toFixed(0);
return Deluge.progressBar(progress, this.width - 8, progress + '%');
}
Deluge.details.PeersTab = Ext.extend(Ext.grid.GridPanel, {
// fast way to figure out if we have a peer already.
peers: {},
constructor: function(config) {
config = Ext.apply({
title: _('Peers'), title: _('Peers'),
cls: 'x-deluge-peers', cls: 'x-deluge-peers',
store: new Ext.data.Store({ viewConfig: {
reader: new Ext.data.JsonReader({ loadMask: false
idProperty: 'ip', },
invalidateScrollerOnRefresh: false,
store: {
model: 'Deluge.data.Peer',
proxy: {
type: 'ajax',
url: 'peers/',
reader: {
type: 'json',
root: 'peers' root: 'peers'
}, Deluge.data.Peer) }
}), }
},
columns: [{ columns: [{
header: '&nbsp;', text: '&nbsp;',
dataIndex: 'country',
width: 30, width: 30,
sortable: true, sortable: true,
renderer: flagRenderer, renderer: function(v) {
dataIndex: 'country' if (!v.replace(' ', '').replace(' ', '')) {
return '';
}
return Ext.String.format('<img src="flag/{0}" />', v);
}
}, { }, {
header: 'Address', text: 'Address',
dataIndex: 'ip',
width: 125, width: 125,
sortable: true, sortable: true,
renderer: peerAddressRenderer, renderer: function(v, p, r) {
dataIndex: 'ip' var cls = (r.data['seed'] == 1024) ? 'x-deluge-seed': 'x-deluge-peer';
return Ext.String.format('<div class="{0}">{1}</div>', cls, v);
}
}, { }, {
header: 'Client', text: 'Client',
dataIndex: 'client',
width: 125, width: 125,
sortable: true, sortable: true,
renderer: fplain, renderer: function(v) { return fplain(v) }
dataIndex: 'client'
}, { }, {
header: 'Progress', text: 'Progress',
dataIndex: 'progress',
width: 150, width: 150,
sortable: true, sortable: true,
renderer: peerProgressRenderer, renderer: function(v) {
dataIndex: 'progress' var progress = (v * 100).toFixed(0),
width = this.query('gridcolumn[dataIndex=progress]')[0].getWidth();
return Deluge.progressBar(progress, width - 8, progress + '%');
}
}, { }, {
header: 'Down Speed', text: 'Down Speed',
dataIndex: 'down_speed',
width: 100, width: 100,
sortable: true, sortable: true,
renderer: fspeed, renderer: function(v) { return fspeed(v) }
dataIndex: 'down_speed'
}, { }, {
header: 'Up Speed', text: 'Up Speed',
dataIndex: 'up_speed',
width: 100, width: 100,
sortable: true, sortable: true,
renderer: fspeed, renderer: function(v) { return fspeed(v) }
dataIndex: 'up_speed'
}], }],
stripeRows: true,
autoScroll: true,
deferredRender: false, deferredRender: false,
autoScroll:true stripeRows: true,
}, config);
Deluge.details.PeersTab.superclass.constructor.call(this, config);
},
clear: function() { clear: function() {
this.getStore().removeAll(); this.getStore().removeAll();
this.peers = {};
}, },
update: function(torrentId) { update: function(torrentId) {
deluge.client.web.get_torrent_status(torrentId, Deluge.Keys.Peers, { var store = this.getStore(),
success: this.onRequestComplete, view = this.getView();
scope: this
});
},
onRequestComplete: function(torrent, options) { if (torrentId != this.torrentId) {
if (!torrent) return; store.removeAll();
store.getProxy().url = 'peers/' + torrentId;
var store = this.getStore(); this.torrentId = torrentId;
var newPeers = [];
var addresses = {};
// Go through the peers updating and creating peer records
Ext.each(torrent.peers, function(peer) {
if (this.peers[peer.ip]) {
var record = store.getById(peer.ip);
record.beginEdit();
for (var k in peer) {
if (record.get(k) != peer[k]) {
record.set(k, peer[k]);
} }
} store.load();
record.endEdit();
} else {
this.peers[peer.ip] = 1;
newPeers.push(new Deluge.data.Peer(peer, peer.ip));
}
addresses[peer.ip] = 1;
}, this);
store.add(newPeers);
// Remove any peers that shouldn't be left in the store
store.each(function(record) {
if (!addresses[record.id]) {
store.remove(record);
delete this.peers[record.id];
}
}, this);
store.commitChanges();
var sortState = store.getSortState();
if (!sortState) return;
store.sort(sortState.field, sortState.direction);
} }
}); });
})();

View File

@ -1,7 +1,7 @@
/*! /*!
* Ext.ux.layout.FormLayoutFix.js * Deluge.details.StatusItem.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -30,27 +30,46 @@
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
// Taken from http://extjs.com/forum/showthread.php?t=75273 /**
// remove spaces for hidden elements and make show(), hide(), enable() and disable() act on * @class Deluge.details.StatusItem
// the label. don't use hideLabel with this. * @extends Ext.Component
Ext.override(Ext.layout.FormLayout, { */
renderItem : function(c, position, target){ Ext.define('Deluge.details.StatusItem', {
if(c && !c.rendered && (c.isFormField || c.fieldLabel) && c.inputType != 'hidden'){ extend: 'Ext.Component',
var args = this.getTemplateArgs(c); alias: 'widget.statusitem',
if(typeof position == 'number'){
position = target.dom.childNodes[position] || null; renderTpl:
} '<div class="x-status-item">' +
if(position){ '<span class="x-status-label" style="width: {labelWidth}px;">{label}:</span>' +
c.formItem = this.fieldTpl.insertBefore(position, args, true); '<span class="x-status-text">{text}</span>' +
}else{ '</div>',
c.formItem = this.fieldTpl.append(target, args, true);
} renderSelectors: {
c.actionMode = 'formItem'; labelEl: 'span.x-status-label',
c.render('x-form-el-'+c.id); textEl: 'span.x-status-text'
c.container = c.formItem; },
c.actionMode = 'container';
}else {
Ext.layout.FormLayout.superclass.renderItem.apply(this, arguments); initComponent: function() {
} var me = this;
me.callParent(arguments);
},
setText: function(text) {
var me = this;
me.textEl.dom.innerHTML = text;
},
// private
onRender: function(ct, position) {
var me = this;
Ext.applyIf(me.renderData, {
label: me.label,
labelWidth: me.labelWidth || 0,
text: me.text
});
me.callParent(arguments);
} }
}); });

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.details.StatusTab.js * Deluge.details.StatusTab.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,42 +29,134 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.ns('Deluge.details');
/** /**
* @class Deluge.details.StatusTab * @class Deluge.details.StatusTab
* @extends Ext.Panel * @extends Ext.panel.Panel
*/ */
Deluge.details.StatusTab = Ext.extend(Ext.Panel, { Ext.define('Deluge.details.StatusTab', {
extend: 'Ext.panel.Panel',
title: _('Status'), title: _('Status'),
autoScroll: true, autoScroll: true,
bodyPadding: 10,
onRender: function(ct, position) { layout: {
Deluge.details.StatusTab.superclass.onRender.call(this, ct, position); type: 'vbox',
align: 'stretch'
this.progressBar = this.add({
xtype: 'progress',
cls: 'x-deluge-status-progressbar'
});
this.status = this.add({
cls: 'x-deluge-status',
id: 'deluge-details-status',
border: false,
width: 1000,
listeners: {
'render': {
fn: function(panel) {
panel.load({
url: deluge.config.base + 'render/tab_status.html',
text: _('Loading') + '...'
});
panel.getUpdater().on('update', this.onPanelUpdate, this);
}, },
initComponent: function() {
this.callParent(arguments);
this.fields = {};
this.progressBar = this.add({
xtype: 'progressbar',
cls: 'x-deluge-torrent-progressbar'
});
this.add({
xtype: 'container',
margins: 10,
border: false,
flex: 1,
layout: {
type: 'hbox',
align: 'stretch'
},
defaultType: 'container',
defaults: {
flex: 1,
layout: 'vbox',
border: false,
defaultType: 'statusitem'
},
items: [{
defaults: {
labelWidth: 100,
width: 300,
margins: '2 0 2 0'
},
items: [{
label: _('Downloaded'),
dataIndex: 'downloaded'
}, {
label: _('Uploaded'),
dataIndex: 'uploaded'
}, {
label: _('Share Ratio'),
dataIndex: 'share'
}, {
label: _('Next Announce'),
dataIndex: 'announce'
}, {
label: _('Tracker Status'),
dataIndex: 'tracker_status'
}]
}, {
defaults: {
labelWidth: 55,
width: 300
},
items: [{
label: _('Speed'),
dataIndex: 'downspeed'
}, {
label: _('Speed'),
dataIndex: 'upspeed'
}, {
label: _('ETA'),
dataIndex: 'eta'
}, {
label: _('Pieces'),
dataIndex: 'pieces'
}]
}, {
defaults: {
labelWidth: 130,
width: 300
},
items: [{
label: _('Seeders'),
dataIndex: 'seeders'
}, {
label: _('Peers'),
dataIndex: 'peers'
}, {
label: _('Availability'),
dataIndex: 'avail'
}, {
label: _('Auto Managed'),
dataIndex: 'auto_managed'
}, {
label: _('Last Seen Complete'),
dataIndex: 'last_seen_complete'
}]
}, {
defaults: {
labelWidth: 100,
width: 300
},
items: [{
label: _('Active Time'),
dataIndex: 'active_time'
}, {
label: _('Seeding Time'),
dataIndex: 'seeding_time'
}, {
label: _('Seed Rank'),
dataIndex: 'seed_rank'
}, {
label: _('Date Added'),
dataIndex: 'time_added'
}]
}]
});
},
update: function(torrentId) {
deluge.client.web.get_torrent_status(torrentId, Deluge.Keys.Status, {
success: this.onRequestComplete,
scope: this scope: this
}
}
}); });
}, },
@ -75,53 +167,42 @@ Deluge.details.StatusTab = Ext.extend(Ext.Panel, {
} }
}, },
update: function(torrentId) { onRequestComplete: function(torrent) {
if (!this.fields) this.getFields(); var me = this;
deluge.client.web.get_torrent_status(torrentId, Deluge.Keys.Status, {
success: this.onRequestComplete,
scope: this
});
},
onPanelUpdate: function(el, response) { var text = torrent.state + ' ' + torrent.progress.toFixed(2) + '%';
this.fields = {}; me.progressBar.updateProgress(torrent.progress / 100.0, text);
Ext.each(Ext.query('dd', this.status.body.dom), function(field) {
this.fields[field.className] = field;
}, this);
},
onRequestComplete: function(status) { seeders = torrent.total_seeds > -1 ? torrent.num_seeds + ' (' + torrent.total_seeds + ')' : torrent.num_seeds;
seeders = status.total_seeds > -1 ? status.num_seeds + ' (' + status.total_seeds + ')' : status.num_seeds; peers = torrent.total_peers > -1 ? torrent.num_peers + ' (' + torrent.total_peers + ')' : torrent.num_peers;
peers = status.total_peers > -1 ? status.num_peers + ' (' + status.total_peers + ')' : status.num_peers; last_seen_complete = torrent.last_seen_complete > 0.0 ? fdate(torrent.last_seen_complete) : "Never";
last_seen_complete = status.last_seen_complete > 0.0 ? fdate(status.last_seen_complete) : "Never";
var data = { var data = {
downloaded: fsize(status.total_done, true), downloaded: fsize(torrent.total_done, true),
uploaded: fsize(status.total_uploaded, true), uploaded: fsize(torrent.total_uploaded, true),
share: (status.ratio == -1) ? '&infin;' : status.ratio.toFixed(3), share: (torrent.ratio == -1) ? '&infin;' : torrent.ratio.toFixed(3),
announce: ftime(status.next_announce), announce: ftime(torrent.next_announce),
tracker_status: status.tracker_status, tracker_status: torrent.tracker_status,
downspeed: (status.download_payload_rate) ? fspeed(status.download_payload_rate) : '0.0 KiB/s', tracker_torrent: torrent.tracker_torrent,
upspeed: (status.upload_payload_rate) ? fspeed(status.upload_payload_rate) : '0.0 KiB/s', downspeed: (torrent.download_payload_rate) ? fspeed(torrent.download_payload_rate) : '0.0 KiB/s',
eta: ftime(status.eta), upspeed: (torrent.upload_payload_rate) ? fspeed(torrent.upload_payload_rate) : '0.0 KiB/s',
pieces: status.num_pieces + ' (' + fsize(status.piece_length) + ')', eta: ftime(torrent.eta),
pieces: torrent.num_pieces + ' (' + fsize(torrent.piece_length) + ')',
seeders: seeders, seeders: seeders,
peers: peers, peers: peers,
avail: status.distributed_copies.toFixed(3), avail: torrent.distributed_copies.toFixed(3),
active_time: ftime(status.active_time), active_time: ftime(torrent.active_time),
seeding_time: ftime(status.seeding_time), seeding_time: ftime(torrent.seeding_time),
seed_rank: status.seed_rank, seed_rank: torrent.seed_rank,
time_added: fdate(status.time_added), time_added: fdate(torrent.time_added),
last_seen_complete: last_seen_complete last_seen_complete: last_seen_complete
} }
data.auto_managed = _((status.is_auto_managed) ? 'True' : 'False'); data.auto_managed = _((torrent.is_auto_managed) ? 'True' : 'False');
data.downloaded += ' (' + ((status.total_payload_download) ? fsize(status.total_payload_download) : '0.0 KiB') + ')'; data.downloaded += ' (' + ((torrent.total_payload_download) ? fsize(torrent.total_payload_download) : '0.0 KiB') + ')';
data.uploaded += ' (' + ((status.total_payload_download) ? fsize(status.total_payload_download): '0.0 KiB') + ')'; data.uploaded += ' (' + ((torrent.total_payload_download) ? fsize(torrent.total_payload_download): '0.0 KiB') + ')';
for (var field in this.fields) { Ext.Array.each(me.query('statusitem'), function(item) {
this.fields[field].innerHTML = data[field]; item.setText(data[item.dataIndex]);
} }, me);
var text = status.state + ' ' + status.progress.toFixed(2) + '%';
this.progressBar.updateProgress(status.progress / 100.0, text);
} }
}); });

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.preferences.BandwidthPage.js * Deluge.preferences.BandwidthPage.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,25 +29,20 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.namespace('Deluge.preferences');
/** /**
* @class Deluge.preferences.Bandwidth * @class Deluge.preferences.Bandwidth
* @extends Ext.form.FormPanel * @extends Ext.form.FormPanel
*/ */
Deluge.preferences.Bandwidth = Ext.extend(Ext.form.FormPanel, { Ext.define('Deluge.preferences.Bandwidth', {
constructor: function(config) { extend: 'Ext.form.Panel',
config = Ext.apply({
border: false, border: false,
title: _('Bandwidth'), title: _('Bandwidth'),
layout: 'form', labelWidth: 10,
labelWidth: 10
}, config);
Deluge.preferences.Bandwidth.superclass.constructor.call(this, config);
},
initComponent: function() { initComponent: function() {
Deluge.preferences.Bandwidth.superclass.initComponent.call(this); this.callParent(arguments);
var om = deluge.preferences.getOptionsManager(); var om = deluge.preferences.getOptionsManager();
var fieldset = this.add({ var fieldset = this.add({

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.preferences.CachePage.js * Deluge.preferences.CachePage.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,20 +29,19 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.namespace('Deluge.preferences');
/** /**
* @class Deluge.preferences.Cache * @class Deluge.preferences.Cache
* @extends Ext.form.FormPanel * @extends Ext.form.FormPanel
*/ */
Deluge.preferences.Cache = Ext.extend(Ext.form.FormPanel, { Ext.define('Deluge.preferences.Cache', {
extend: 'Ext.form.Panel',
border: false, border: false,
title: _('Cache'), title: _('Cache'),
layout: 'form',
initComponent: function() { initComponent: function() {
Deluge.preferences.Cache.superclass.initComponent.call(this); this.callParent(arguments);
var om = deluge.preferences.getOptionsManager(); var om = deluge.preferences.getOptionsManager();

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.preferences.DaemonPage.js * Deluge.preferences.DaemonPage.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,20 +29,19 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.namespace('Deluge.preferences');
/** /**
* @class Deluge.preferences.Daemon * @class Deluge.preferences.Daemon
* @extends Ext.form.FormPanel * @extends Ext.form.FormPanel
*/ */
Deluge.preferences.Daemon = Ext.extend(Ext.form.FormPanel, { Ext.define('Deluge.preferences.Daemon', {
extend: 'Ext.form.Panel',
border: false, border: false,
title: _('Daemon'), title: _('Daemon'),
layout: 'form',
initComponent: function() { initComponent: function() {
Deluge.preferences.Daemon.superclass.initComponent.call(this); this.callParent(arguments);
var om = deluge.preferences.getOptionsManager(); var om = deluge.preferences.getOptionsManager();

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.preferences.DownloadsPage.js * Deluge.preferences.DownloadsPage.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,26 +29,21 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.namespace('Deluge.preferences');
/** /**
* @class Deluge.preferences.Downloads * @class Deluge.preferences.Downloads
* @extends Ext.form.FormPanel * @extends Ext.form.FormPanel
*/ */
Deluge.preferences.Downloads = Ext.extend(Ext.FormPanel, { Ext.define('Deluge.preferences.Downloads', {
constructor: function(config) { extend: 'Ext.form.Panel',
config = Ext.apply({
border: false, border: false,
title: _('Downloads'), title: _('Downloads'),
layout: 'form', layout: 'anchor',
autoHeight: true, autoHeight: true,
width: 320 width: 320,
}, config);
Deluge.preferences.Downloads.superclass.constructor.call(this, config);
},
initComponent: function() { initComponent: function() {
Deluge.preferences.Downloads.superclass.initComponent.call(this); this.callParent(arguments);
var optMan = deluge.preferences.getOptionsManager(); var optMan = deluge.preferences.getOptionsManager();
var fieldset = this.add({ var fieldset = this.add({

View File

@ -57,7 +57,7 @@ Deluge.preferences.Encryption = Ext.extend(Ext.form.FormPanel, {
fieldLabel: _('Inbound'), fieldLabel: _('Inbound'),
mode: 'local', mode: 'local',
width: 150, width: 150,
store: new Ext.data.ArrayStore({ store: Ext.create('Ext.data.Store', {
fields: ['id', 'text'], fields: ['id', 'text'],
data: [ data: [
[0, _('Forced')], [0, _('Forced')],
@ -74,7 +74,7 @@ Deluge.preferences.Encryption = Ext.extend(Ext.form.FormPanel, {
fieldLabel: _('Outbound'), fieldLabel: _('Outbound'),
mode: 'local', mode: 'local',
width: 150, width: 150,
store: new Ext.data.SimpleStore({ store: Ext.create('Ext.data.Store', {
fields: ['id', 'text'], fields: ['id', 'text'],
data: [ data: [
[0, _('Forced')], [0, _('Forced')],
@ -91,7 +91,7 @@ Deluge.preferences.Encryption = Ext.extend(Ext.form.FormPanel, {
fieldLabel: _('Level'), fieldLabel: _('Level'),
mode: 'local', mode: 'local',
width: 150, width: 150,
store: new Ext.data.SimpleStore({ store: Ext.create('Ext.data.Store', {
fields: ['id', 'text'], fields: ['id', 'text'],
data: [ data: [
[0, _('Handshake')], [0, _('Handshake')],

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.preferences.InterfacePage.js * Deluge.preferences.InterfacePage.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,20 +29,19 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.namespace('Deluge.preferences');
/** /**
* @class Deluge.preferences.Interface * @class Deluge.preferences.Interface
* @extends Ext.form.FormPanel * @extends Ext.form.FormPanel
*/ */
Deluge.preferences.Interface = Ext.extend(Ext.form.FormPanel, { Ext.define('Deluge.preferences.Interface', {
extend: 'Ext.form.Panel',
border: false, border: false,
title: _('Interface'), title: _('Interface'),
layout: 'form',
initComponent: function() { initComponent: function() {
Deluge.preferences.Interface.superclass.initComponent.call(this); this.callParent(arguments);
var om = this.optionsManager = new Deluge.OptionsManager(); var om = this.optionsManager = new Deluge.OptionsManager();
this.on('show', this.onPageShow, this); this.on('show', this.onPageShow, this);

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.preferences.NetworkPage.js * Deluge.preferences.NetworkPage.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,20 +29,19 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.namespace('Deluge.preferences');
/** /**
* @class Deluge.preferences.Network * @class Deluge.preferences.Network
* @extends Ext.form.FormPanel * @extends Ext.form.FormPanel
*/ */
Deluge.preferences.Network = Ext.extend(Ext.form.FormPanel, { Ext.define('Deluge.preferences.Network', {
extend: 'Ext.form.Panel',
border: false, border: false,
layout: 'form',
title: _('Network'), title: _('Network'),
initComponent: function() { initComponent: function() {
Deluge.preferences.Network.superclass.initComponent.call(this); this.callParent(arguments);
var optMan = deluge.preferences.getOptionsManager(); var optMan = deluge.preferences.getOptionsManager();
var fieldset = this.add({ var fieldset = this.add({

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.preferences.OtherPage.js * Deluge.preferences.OtherPage.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,24 +29,18 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.namespace('Deluge.preferences');
/** /**
* @class Deluge.preferences.Other * @class Deluge.preferences.Other
* @extends Ext.form.FormPanel * @extends Ext.form.FormPanel
*/ */
Deluge.preferences.Other = Ext.extend(Ext.form.FormPanel, { Ext.define('Deluge.preferences.Other', {
constructor: function(config) { extend: 'Ext.form.Panel',
config = Ext.apply({
border: false, border: false,
title: _('Other'), title: _('Other'),
layout: 'form'
}, config);
Deluge.preferences.Other.superclass.constructor.call(this, config);
},
initComponent: function() { initComponent: function() {
Deluge.preferences.Other.superclass.initComponent.call(this); this.callParent(arguments);
var optMan = deluge.preferences.getOptionsManager(); var optMan = deluge.preferences.getOptionsManager();

View File

@ -29,7 +29,6 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.namespace('Deluge.preferences');
/** /**
* @class Deluge.preferences.Plugins * @class Deluge.preferences.Plugins
@ -43,7 +42,7 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
height: 400, height: 400,
cls: 'x-deluge-plugins', cls: 'x-deluge-plugins',
pluginTemplate: new Ext.Template( pluginTemplate: Ext.create('Ext.Template',
'<dl class="singleline">' + '<dl class="singleline">' +
'<dt>Author:</dt><dd>{author}</dd>' + '<dt>Author:</dt><dd>{author}</dd>' +
'<dt>Version:</dt><dd>{version}</dd>' + '<dt>Version:</dt><dd>{version}</dd>' +
@ -54,7 +53,8 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
), ),
initComponent: function() { initComponent: function() {
Deluge.preferences.Plugins.superclass.initComponent.call(this); console.log('Plugins preferences page created');
this.callParent(arguments);
this.defaultValues = { this.defaultValues = {
'version': '', 'version': '',
'email': '', 'email': '',
@ -68,20 +68,23 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
return '<div class="x-grid3-check-col'+(v?'-on':'')+'"> </div>'; return '<div class="x-grid3-check-col'+(v?'-on':'')+'"> </div>';
} }
this.list = this.add({
xtype: 'listview',
store: new Ext.data.ArrayStore({ this.grid = this.add({
fields: [ xtype: 'grid',
{name: 'enabled', mapping: 0}, store: Ext.create('Ext.data.Store', {
{name: 'plugin', mapping: 1} model: 'Deluge.data.Plugin',
] proxy: {
type: 'memory'
}
}), }),
singleSelect: true,
columns: [{ columns: [{
id: 'enabled', id: 'enabled',
header: _('Enabled'), header: _('Enabled'),
width: .2, width: .2,
sortable: true, sortable: true,
tpl: new Ext.XTemplate('{enabled:this.getCheckbox}', { tpl: Ext.create('Ext.XTemplate', '{enabled:this.getCheckbox}', {
getCheckbox: function(v) { getCheckbox: function(v) {
return '<div class="x-grid3-check-col'+(v?'-on':'')+'" rel="chkbox"> </div>'; return '<div class="x-grid3-check-col'+(v?'-on':'')+'" rel="chkbox"> </div>';
} }
@ -94,8 +97,6 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
sortable: true, sortable: true,
dataIndex: 'plugin' dataIndex: 'plugin'
}], }],
singleSelect: true,
autoExpandColumn: 'plugin',
listeners: { listeners: {
selectionchange: {fn: this.onPluginSelect, scope: this} selectionchange: {fn: this.onPluginSelect, scope: this}
} }
@ -105,8 +106,8 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
region: 'center', region: 'center',
autoScroll: true, autoScroll: true,
margins: '5 5 5 5', margins: '5 5 5 5',
items: [this.list], items: [this.grid],
bbar: new Ext.Toolbar({ bbar: {
items: [{ items: [{
cls: 'x-btn-text-icon', cls: 'x-btn-text-icon',
iconCls: 'x-deluge-install-plugin', iconCls: 'x-deluge-install-plugin',
@ -120,7 +121,7 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
handler: this.onFindMorePlugins, handler: this.onFindMorePlugins,
scope: this scope: this
}] }]
}) }
}); });
var pp = this.pluginInfo = this.add({ var pp = this.pluginInfo = this.add({
@ -147,7 +148,7 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
}); });
this.pluginInfo.on('render', this.onPluginInfoRender, this); this.pluginInfo.on('render', this.onPluginInfoRender, this);
this.list.on('click', this.onNodeClick, this); this.grid.on('click', this.onNodeClick, this);
deluge.preferences.on('show', this.onPreferencesShow, this); deluge.preferences.on('show', this.onPreferencesShow, this);
deluge.events.on('PluginDisabledEvent', this.onPluginDisabled, this); deluge.events.on('PluginDisabledEvent', this.onPluginDisabled, this);
deluge.events.on('PluginEnabledEvent', this.onPluginEnabled, this); deluge.events.on('PluginEnabledEvent', this.onPluginEnabled, this);
@ -187,7 +188,7 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
}, },
onNodeClick: function(dv, index, node, e) { onNodeClick: function(dv, index, node, e) {
var el = new Ext.Element(e.target); var el = Ext.fly(e.target);
if (el.getAttribute('rel') != 'chkbox') return; if (el.getAttribute('rel') != 'chkbox') return;
var r = dv.getStore().getAt(index); var r = dv.getStore().getAt(index);
@ -225,7 +226,7 @@ Deluge.preferences.Plugins = Ext.extend(Ext.Panel, {
onInstallPluginWindow: function() { onInstallPluginWindow: function() {
if (!this.installWindow) { if (!this.installWindow) {
this.installWindow = new Deluge.preferences.InstallPluginWindow(); this.installWindow = Ext.create('Deluge.preferences.InstallPluginWindow');
this.installWindow.on('pluginadded', this.onPluginInstall, this); this.installWindow.on('pluginadded', this.onPluginInstall, this);
} }
this.installWindow.show(); this.installWindow.show();

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.preferences.PreferencesWindow.js * Deluge.preferences.PreferencesWindow.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,15 +29,13 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.namespace('Deluge.preferences');
PreferencesRecord = Ext.data.Record.create([{name:'name', type:'string'}]);
/** /**
* @class Deluge.preferences.PreferencesWindow * @class Deluge.preferences.PreferencesWindow
* @extends Ext.Window * @extends Ext.Window
*/ */
Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, { Ext.define('Deluge.preferences.PreferencesWindow', {
extend: 'Ext.Window',
/** /**
* @property {String} currentPage The currently selected page. * @property {String} currentPage The currently selected page.
@ -59,14 +57,16 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
pages: {}, pages: {},
initComponent: function() { initComponent: function() {
Deluge.preferences.PreferencesWindow.superclass.initComponent.call(this); this.callParent(arguments);
this.list = new Ext.list.ListView({ this.list = Ext.create('Ext.list.ListView', {
store: new Ext.data.Store(), store: Ext.create('Ext.data.Store', {
model: 'Deluge.data.Preferences'
}),
columns: [{ columns: [{
id: 'name',
renderer: fplain, renderer: fplain,
dataIndex: 'name' dataIndex: 'name',
flex: 1
}], }],
singleSelect: true, singleSelect: true,
listeners: { listeners: {
@ -75,7 +75,6 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
} }
}, },
hideHeaders: true, hideHeaders: true,
autoExpandColumn: 'name',
deferredRender: false, deferredRender: false,
autoScroll: true, autoScroll: true,
collapsible: true collapsible: true
@ -103,30 +102,30 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
cmargins: '5 5 5 5' cmargins: '5 5 5 5'
}); });
this.addButton(_('Close'), this.onClose, this); //this.addButton(_('Close'), this.onClose, this);
this.addButton(_('Apply'), this.onApply, this); //this.addButton(_('Apply'), this.onApply, this);
this.addButton(_('Ok'), this.onOk, this); //this.addButton(_('Ok'), this.onOk, this);
this.optionsManager = new Deluge.OptionsManager(); this.optionsManager = Ext.create('Deluge.OptionsManager');
this.on('afterrender', this.onAfterRender, this); this.on('afterrender', this.onAfterRender, this);
this.on('show', this.onShow, this);
this.afterMethod('onShow', this.afterShown, this);
this.initPages(); this.initPages();
}, },
initPages: function() { initPages: function() {
deluge.preferences = this; deluge.preferences = this;
this.addPage(new Deluge.preferences.Downloads()); this.addPage(Ext.create('Deluge.preferences.Downloads'));
this.addPage(new Deluge.preferences.Network()); //this.addPage(Ext.create('Deluge.preferences.Network'));
this.addPage(new Deluge.preferences.Encryption()); this.addPage(Ext.create('Deluge.preferences.Encryption'));
this.addPage(new Deluge.preferences.Bandwidth()); this.addPage(Ext.create('Deluge.preferences.Bandwidth'));
this.addPage(new Deluge.preferences.Interface()); this.addPage(Ext.create('Deluge.preferences.Interface'));
this.addPage(new Deluge.preferences.Other()); this.addPage(Ext.create('Deluge.preferences.Other'));
this.addPage(new Deluge.preferences.Daemon()); this.addPage(Ext.create('Deluge.preferences.Daemon'));
this.addPage(new Deluge.preferences.Queue()); this.addPage(Ext.create('Deluge.preferences.Queue'));
this.addPage(new Deluge.preferences.Proxy()); this.addPage(Ext.create('Deluge.preferences.Proxy'));
this.addPage(new Deluge.preferences.Cache()); this.addPage(Ext.create('Deluge.preferences.Cache'));
this.addPage(new Deluge.preferences.Plugins()); this.addPage(Ext.create('Deluge.preferences.Plugins'));
}, },
onApply: function(e) { onApply: function(e) {
@ -159,7 +158,7 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
addPage: function(page) { addPage: function(page) {
var store = this.list.getStore(); var store = this.list.getStore();
var name = page.title; var name = page.title;
store.add([new PreferencesRecord({name: name})]); store.add({name: name});
page['bodyStyle'] = 'padding: 5px'; page['bodyStyle'] = 'padding: 5px';
page.preferences = this; page.preferences = this;
this.pages[name] = this.configPanel.add(page); this.pages[name] = this.configPanel.add(page);
@ -224,7 +223,7 @@ Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, {
}, },
// private // private
onShow: function() { afterShown: function() {
if (!deluge.client.core) return; if (!deluge.client.core) return;
deluge.client.core.get_config({ deluge.client.core.get_config({
success: this.onGotConfig, success: this.onGotConfig,

View File

@ -49,7 +49,7 @@ Deluge.preferences.ProxyField = Ext.extend(Ext.form.FieldSet, {
name: 'proxytype', name: 'proxytype',
mode: 'local', mode: 'local',
width: 150, width: 150,
store: new Ext.data.ArrayStore({ store: Ext.create('Ext.data.Store', {
fields: ['id', 'text'], fields: ['id', 'text'],
data: [ data: [
[0, _('None')], [0, _('None')],

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.preferences.ProxyPage.js * Deluge.preferences.ProxyPage.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,43 +29,38 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.namespace('Deluge.preferences');
/** /**
* @class Deluge.preferences.Proxy * @class Deluge.preferences.Proxy
* @extends Ext.form.FormPanel * @extends Ext.form.FormPanel
*/ */
Deluge.preferences.Proxy = Ext.extend(Ext.form.FormPanel, { Ext.define('Deluge.preferences.Proxy', {
constructor: function(config) { extend: 'Ext.form.Panel',
config = Ext.apply({
border: false, border: false,
title: _('Proxy'), title: _('Proxy'),
layout: 'form'
}, config);
Deluge.preferences.Proxy.superclass.constructor.call(this, config);
},
initComponent: function() { initComponent: function() {
Deluge.preferences.Proxy.superclass.initComponent.call(this); this.callParent(arguments);
this.peer = this.add(new Deluge.preferences.ProxyField({ this.peer = this.add(Ext.create('Deluge.preferences.ProxyField', {
title: _('Peer'), title: _('Peer'),
name: 'peer' name: 'peer'
})); }));
this.peer.on('change', this.onProxyChange, this); this.peer.on('change', this.onProxyChange, this);
this.web_seed = this.add(new Deluge.preferences.ProxyField({ this.web_seed = this.add(Ext.create('Deluge.preferences.ProxyField',{
title: _('Web Seed'), title: _('Web Seed'),
name: 'web_seed' name: 'web_seed'
})); }));
this.web_seed.on('change', this.onProxyChange, this); this.web_seed.on('change', this.onProxyChange, this);
this.tracker = this.add(new Deluge.preferences.ProxyField({ this.tracker = this.add(Ext.create('Deluge.preferences.ProxyField', {
title: _('Tracker'), title: _('Tracker'),
name: 'tracker' name: 'tracker'
})); }));
this.tracker.on('change', this.onProxyChange, this); this.tracker.on('change', this.onProxyChange, this);
this.dht = this.add(new Deluge.preferences.ProxyField({ this.dht = this.add(Ext.create('Deluge.preferences.ProxyField', {
title: _('DHT'), title: _('DHT'),
name: 'dht' name: 'dht'
})); }));

View File

@ -1,7 +1,7 @@
/*! /*!
* Deluge.preferences.QueuePage.js * Deluge.preferences.QueuePage.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,20 +29,19 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.namespace('Deluge.preferences');
/** /**
* @class Deluge.preferences.Queue * @class Deluge.preferences.Queue
* @extends Ext.form.FormPanel * @extends Ext.form.FormPanel
*/ */
Deluge.preferences.Queue = Ext.extend(Ext.form.FormPanel, { Ext.define('Deluge.preferences.Queue', {
extend: 'Ext.form.Panel',
border: false, border: false,
title: _('Queue'), title: _('Queue'),
layout: 'form',
initComponent: function() { initComponent: function() {
Deluge.preferences.Queue.superclass.initComponent.call(this); this.callParent(arguments);
var om = deluge.preferences.getOptionsManager(); var om = deluge.preferences.getOptionsManager();

File diff suppressed because it is too large Load Diff

134730
deluge/ui/web/js/ext-all-dev.js Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

21851
deluge/ui/web/js/ext-debug.js Normal file

File diff suppressed because it is too large Load Diff

22381
deluge/ui/web/js/ext-dev.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,38 +0,0 @@
Ext.ux.JSLoader = function(options) {
Ext.ux.JSLoader.scripts[++Ext.ux.JSLoader.index] = {
url: options.url,
success: true,
jsLoadObj: null,
options: options,
onLoad: options.onLoad || Ext.emptyFn,
onError: options.onError || Ext.ux.JSLoader.stdError,
scope: options.scope || this
};
Ext.Ajax.request({
url: options.url,
scriptIndex: Ext.ux.JSLoader.index,
success: function(response, options) {
var script = Ext.ux.JSLoader.scripts[options.scriptIndex];
try {
eval(response.responseText);
} catch(e) {
script.success = false;
script.onError(script.options, e);
}
if (script.success) {
script.onLoad.call(script.scope, script.options);
}
},
failure: function(response, options) {
var script = Ext.ux.JSLoader.scripts[options.scriptIndex];
script.success = false;
script.onError(script.options, response.status);
}
});
}
Ext.ux.JSLoader.index = 0;
Ext.ux.JSLoader.scripts = [];
Ext.ux.JSLoader.stdError = function(options, e) {
window.alert('Error loading script:\n\n' + options.url + '\n\nstatus: ' + e);
}

View File

@ -1,438 +0,0 @@
/*!
* Ext JS Library 3.1.0
* Copyright(c) 2006-2009 Ext JS, LLC
* licensing@extjs.com
* http://www.extjs.com/license
*/
/**
* @class Ext.ux.Spinner
* @extends Ext.util.Observable
* Creates a Spinner control utilized by Ext.ux.form.SpinnerField
*/
Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
incrementValue: 1,
alternateIncrementValue: 5,
triggerClass: 'x-form-spinner-trigger',
splitterClass: 'x-form-spinner-splitter',
alternateKey: Ext.EventObject.shiftKey,
defaultValue: 0,
accelerate: false,
constructor: function(config){
Ext.ux.Spinner.superclass.constructor.call(this, config);
Ext.apply(this, config);
this.mimicing = false;
},
init: function(field){
this.field = field;
field.afterMethod('onRender', this.doRender, this);
field.afterMethod('onEnable', this.doEnable, this);
field.afterMethod('onDisable', this.doDisable, this);
field.afterMethod('afterRender', this.doAfterRender, this);
field.afterMethod('onResize', this.doResize, this);
field.afterMethod('onFocus', this.doFocus, this);
field.beforeMethod('onDestroy', this.doDestroy, this);
},
doRender: function(ct, position){
var el = this.el = this.field.getEl();
var f = this.field;
if (!f.wrap) {
f.wrap = this.wrap = el.wrap({
cls: "x-form-field-wrap"
});
}
else {
this.wrap = f.wrap.addClass('x-form-field-wrap');
}
this.trigger = this.wrap.createChild({
tag: "img",
src: Ext.BLANK_IMAGE_URL,
cls: "x-form-trigger " + this.triggerClass
});
if (!f.width) {
this.wrap.setWidth(el.getWidth() + this.trigger.getWidth());
}
this.splitter = this.wrap.createChild({
tag: 'div',
cls: this.splitterClass,
style: 'width:13px; height:2px;'
});
this.splitter.setRight((Ext.isIE) ? 1 : 2).setTop(10).show();
this.proxy = this.trigger.createProxy('', this.splitter, true);
this.proxy.addClass("x-form-spinner-proxy");
this.proxy.setStyle('left', '0px');
this.proxy.setSize(14, 1);
this.proxy.hide();
this.dd = new Ext.dd.DDProxy(this.splitter.dom.id, "SpinnerDrag", {
dragElId: this.proxy.id
});
this.initTrigger();
this.initSpinner();
},
doAfterRender: function(){
var y;
if (Ext.isIE && this.el.getY() != (y = this.trigger.getY())) {
this.el.position();
this.el.setY(y);
}
},
doEnable: function(){
if (this.wrap) {
this.wrap.removeClass(this.field.disabledClass);
}
},
doDisable: function(){
if (this.wrap) {
this.wrap.addClass(this.field.disabledClass);
this.el.removeClass(this.field.disabledClass);
}
},
doResize: function(w, h){
if (typeof w == 'number') {
this.el.setWidth(w - this.trigger.getWidth());
}
this.wrap.setWidth(this.el.getWidth() + this.trigger.getWidth());
},
doFocus: function(){
if (!this.mimicing) {
this.wrap.addClass('x-trigger-wrap-focus');
this.mimicing = true;
Ext.get(Ext.isIE ? document.body : document).on("mousedown", this.mimicBlur, this, {
delay: 10
});
this.el.on('keydown', this.checkTab, this);
}
},
// private
checkTab: function(e){
if (e.getKey() == e.TAB) {
this.triggerBlur();
}
},
// private
mimicBlur: function(e){
if (!this.wrap.contains(e.target) && this.field.validateBlur(e)) {
this.triggerBlur();
}
},
// private
triggerBlur: function(){
this.mimicing = false;
Ext.get(Ext.isIE ? document.body : document).un("mousedown", this.mimicBlur, this);
this.el.un("keydown", this.checkTab, this);
this.field.beforeBlur();
this.wrap.removeClass('x-trigger-wrap-focus');
this.field.onBlur.call(this.field);
},
initTrigger: function(){
this.trigger.addClassOnOver('x-form-trigger-over');
this.trigger.addClassOnClick('x-form-trigger-click');
},
initSpinner: function(){
this.field.addEvents({
'spin': true,
'spinup': true,
'spindown': true
});
this.keyNav = new Ext.KeyNav(this.el, {
"up": function(e){
e.preventDefault();
this.onSpinUp();
},
"down": function(e){
e.preventDefault();
this.onSpinDown();
},
"pageUp": function(e){
e.preventDefault();
this.onSpinUpAlternate();
},
"pageDown": function(e){
e.preventDefault();
this.onSpinDownAlternate();
},
scope: this
});
this.repeater = new Ext.util.ClickRepeater(this.trigger, {
accelerate: this.accelerate
});
this.field.mon(this.repeater, "click", this.onTriggerClick, this, {
preventDefault: true
});
this.field.mon(this.trigger, {
mouseover: this.onMouseOver,
mouseout: this.onMouseOut,
mousemove: this.onMouseMove,
mousedown: this.onMouseDown,
mouseup: this.onMouseUp,
scope: this,
preventDefault: true
});
this.field.mon(this.wrap, "mousewheel", this.handleMouseWheel, this);
this.dd.setXConstraint(0, 0, 10)
this.dd.setYConstraint(1500, 1500, 10);
this.dd.endDrag = this.endDrag.createDelegate(this);
this.dd.startDrag = this.startDrag.createDelegate(this);
this.dd.onDrag = this.onDrag.createDelegate(this);
},
onMouseOver: function(){
if (this.disabled) {
return;
}
var middle = this.getMiddle();
this.tmpHoverClass = (Ext.EventObject.getPageY() < middle) ? 'x-form-spinner-overup' : 'x-form-spinner-overdown';
this.trigger.addClass(this.tmpHoverClass);
},
//private
onMouseOut: function(){
this.trigger.removeClass(this.tmpHoverClass);
},
//private
onMouseMove: function(){
if (this.disabled) {
return;
}
var middle = this.getMiddle();
if (((Ext.EventObject.getPageY() > middle) && this.tmpHoverClass == "x-form-spinner-overup") ||
((Ext.EventObject.getPageY() < middle) && this.tmpHoverClass == "x-form-spinner-overdown")) {
}
},
//private
onMouseDown: function(){
if (this.disabled) {
return;
}
var middle = this.getMiddle();
this.tmpClickClass = (Ext.EventObject.getPageY() < middle) ? 'x-form-spinner-clickup' : 'x-form-spinner-clickdown';
this.trigger.addClass(this.tmpClickClass);
},
//private
onMouseUp: function(){
this.trigger.removeClass(this.tmpClickClass);
},
//private
onTriggerClick: function(){
if (this.disabled || this.el.dom.readOnly) {
return;
}
var middle = this.getMiddle();
var ud = (Ext.EventObject.getPageY() < middle) ? 'Up' : 'Down';
this['onSpin' + ud]();
},
//private
getMiddle: function(){
var t = this.trigger.getTop();
var h = this.trigger.getHeight();
var middle = t + (h / 2);
return middle;
},
//private
//checks if control is allowed to spin
isSpinnable: function(){
if (this.disabled || this.el.dom.readOnly) {
Ext.EventObject.preventDefault(); //prevent scrolling when disabled/readonly
return false;
}
return true;
},
handleMouseWheel: function(e){
//disable scrolling when not focused
if (this.wrap.hasClass('x-trigger-wrap-focus') == false) {
return;
}
var delta = e.getWheelDelta();
if (delta > 0) {
this.onSpinUp();
e.stopEvent();
}
else
if (delta < 0) {
this.onSpinDown();
e.stopEvent();
}
},
//private
startDrag: function(){
this.proxy.show();
this._previousY = Ext.fly(this.dd.getDragEl()).getTop();
},
//private
endDrag: function(){
this.proxy.hide();
},
//private
onDrag: function(){
if (this.disabled) {
return;
}
var y = Ext.fly(this.dd.getDragEl()).getTop();
var ud = '';
if (this._previousY > y) {
ud = 'Up';
} //up
if (this._previousY < y) {
ud = 'Down';
} //down
if (ud != '') {
this['onSpin' + ud]();
}
this._previousY = y;
},
//private
onSpinUp: function(){
if (this.isSpinnable() == false) {
return;
}
if (Ext.EventObject.shiftKey == true) {
this.onSpinUpAlternate();
return;
}
else {
this.spin(false, false);
}
this.field.fireEvent("spin", this);
this.field.fireEvent("spinup", this);
},
//private
onSpinDown: function(){
if (this.isSpinnable() == false) {
return;
}
if (Ext.EventObject.shiftKey == true) {
this.onSpinDownAlternate();
return;
}
else {
this.spin(true, false);
}
this.field.fireEvent("spin", this);
this.field.fireEvent("spindown", this);
},
//private
onSpinUpAlternate: function(){
if (this.isSpinnable() == false) {
return;
}
this.spin(false, true);
this.field.fireEvent("spin", this);
this.field.fireEvent("spinup", this);
},
//private
onSpinDownAlternate: function(){
if (this.isSpinnable() == false) {
return;
}
this.spin(true, true);
this.field.fireEvent("spin", this);
this.field.fireEvent("spindown", this);
},
spin: function(down, alternate){
var v = parseFloat(this.field.getValue());
var incr = (alternate == true) ? this.alternateIncrementValue : this.incrementValue;
(down == true) ? v -= incr : v += incr;
v = (isNaN(v)) ? this.defaultValue : v;
v = this.fixBoundries(v);
this.field.setRawValue(v);
},
fixBoundries: function(value){
var v = value;
if (this.field.minValue != undefined && v < this.field.minValue) {
v = this.field.minValue;
}
if (this.field.maxValue != undefined && v > this.field.maxValue) {
v = this.field.maxValue;
}
return this.fixPrecision(v);
},
// private
fixPrecision: function(value){
var nan = isNaN(value);
if (!this.field.allowDecimals || this.field.decimalPrecision == -1 || nan || !value) {
return nan ? '' : value;
}
return parseFloat(parseFloat(value).toFixed(this.field.decimalPrecision));
},
doDestroy: function(){
if (this.trigger) {
this.trigger.remove();
}
if (this.wrap) {
this.wrap.remove();
delete this.field.wrap;
}
if (this.splitter) {
this.splitter.remove();
}
if (this.dd) {
this.dd.unreg();
this.dd = null;
}
if (this.proxy) {
this.proxy.remove();
}
if (this.repeater) {
this.repeater.purgeListeners();
}
}
});
//backwards compat
Ext.form.Spinner = Ext.ux.Spinner;

View File

@ -1,20 +1,28 @@
/*! /*
* Ext JS Library 3.1.0
* Copyright(c) 2006-2009 Ext JS, LLC This file is part of Ext JS 4
* licensing@extjs.com
* http://www.extjs.com/license Copyright (c) 2011 Sencha Inc
Contact: http://www.sencha.com/contact
GNU General Public License Usage
This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
*/ */
/** /**
* @class Ext.ux.StatusBar * @class Ext.ux.StatusBar
* <p>Basic status bar component that can be used as the bottom toolbar of any {@link Ext.Panel}. In addition to * <p>Basic status bar component that can be used as the bottom toolbar of any {@link Ext.Panel}. In addition to
* supporting the standard {@link Ext.Toolbar} interface for adding buttons, menus and other items, the StatusBar * supporting the standard {@link Ext.toolbar.Toolbar} interface for adding buttons, menus and other items, the StatusBar
* provides a greedy status element that can be aligned to either side and has convenient methods for setting the * provides a greedy status element that can be aligned to either side and has convenient methods for setting the
* status text and icon. You can also indicate that something is processing using the {@link #showBusy} method.</p> * status text and icon. You can also indicate that something is processing using the {@link #showBusy} method.</p>
* <pre><code> * <pre><code>
new Ext.Panel({ Ext.create('Ext.Panel', {
title: 'StatusBar', title: 'StatusBar',
// etc. // etc.
bbar: new Ext.ux.StatusBar({ bbar: Ext.create('Ext.ux.StatusBar', {
id: 'my-status', id: 'my-status',
// defaults to use when the status is cleared: // defaults to use when the status is cleared:
@ -47,12 +55,16 @@ sb.showBusy();
sb.clearStatus(); // once completeed sb.clearStatus(); // once completeed
</code></pre> </code></pre>
* @extends Ext.Toolbar * @extends Ext.toolbar.Toolbar
* @constructor * @constructor
* Creates a new StatusBar * Creates a new StatusBar
* @param {Object/Array} config A config object * @param {Object/Array} config A config object
*/ */
Ext.ux.StatusBar = Ext.extend(Ext.Toolbar, { Ext.define('Ext.ux.statusbar.StatusBar', {
extend: 'Ext.toolbar.Toolbar',
alternateClassName: 'Ext.ux.StatusBar',
alias: 'widget.statusbar',
requires: ['Ext.toolbar.TextItem'],
/** /**
* @cfg {String} statusAlign * @cfg {String} statusAlign
* The alignment of the status element within the overall StatusBar layout. When the StatusBar is rendered, * The alignment of the status element within the overall StatusBar layout. When the StatusBar is rendered,
@ -63,10 +75,10 @@ Ext.ux.StatusBar = Ext.extend(Ext.Toolbar, {
* <pre><code> * <pre><code>
// Create a left-aligned status bar containing a button, // Create a left-aligned status bar containing a button,
// separator and text item that will be right-aligned (default): // separator and text item that will be right-aligned (default):
new Ext.Panel({ Ext.create('Ext.Panel', {
title: 'StatusBar', title: 'StatusBar',
// etc. // etc.
bbar: new Ext.ux.StatusBar({ bbar: Ext.create('Ext.ux.StatusBar', {
defaultText: 'Default status text', defaultText: 'Default status text',
id: 'status-id', id: 'status-id',
items: [{ items: [{
@ -78,10 +90,10 @@ new Ext.Panel({
// By adding the statusAlign config, this will create the // By adding the statusAlign config, this will create the
// exact same toolbar, except the status and toolbar item // exact same toolbar, except the status and toolbar item
// layout will be reversed from the previous example: // layout will be reversed from the previous example:
new Ext.Panel({ Ext.create('Ext.Panel', {
title: 'StatusBar', title: 'StatusBar',
// etc. // etc.
bbar: new Ext.ux.StatusBar({ bbar: Ext.create('Ext.ux.StatusBar', {
defaultText: 'Default status text', defaultText: 'Default status text',
id: 'status-id', id: 'status-id',
statusAlign: 'right', statusAlign: 'right',
@ -121,7 +133,7 @@ new Ext.Panel({
} }
// Setting a default icon: // Setting a default icon:
var sb = new Ext.ux.StatusBar({ var sb = Ext.create('Ext.ux.StatusBar', {
defaultIconCls: 'x-status-custom' defaultIconCls: 'x-status-custom'
}); });
@ -184,19 +196,19 @@ sb.setStatus({
// private // private
initComponent : function(){ initComponent : function(){
if(this.statusAlign=='right'){ if (this.statusAlign === 'right') {
this.cls += ' x-status-right'; this.cls += ' x-status-right';
} }
Ext.ux.StatusBar.superclass.initComponent.call(this); this.callParent(arguments);
}, },
// private // private
afterRender : function(){ afterRender : function(){
Ext.ux.StatusBar.superclass.afterRender.call(this); this.callParent(arguments);
var right = this.statusAlign == 'right'; var right = this.statusAlign === 'right';
this.currIconCls = this.iconCls || this.defaultIconCls; this.currIconCls = this.iconCls || this.defaultIconCls;
this.statusEl = new Ext.Toolbar.TextItem({ this.statusEl = Ext.create('Ext.toolbar.TextItem', {
cls: 'x-status-text ' + (this.currIconCls || ''), cls: 'x-status-text ' + (this.currIconCls || ''),
text: this.text || this.defaultText || '' text: this.text || this.defaultText || ''
}); });
@ -208,18 +220,8 @@ sb.setStatus({
this.insert(0, this.statusEl); this.insert(0, this.statusEl);
this.insert(1, '->'); this.insert(1, '->');
} }
this.height = 27;
// this.statusEl = td.createChild({ this.doLayout();
// cls: 'x-status-text ' + (this.iconCls || this.defaultIconCls || ''),
// html: this.text || this.defaultText || ''
// });
// this.statusEl.unselectable();
// this.spacerEl = td.insertSibling({
// tag: 'td',
// style: 'width:100%',
// cn: [{cls:'ytb-spacer'}]
// }, right ? 'before' : 'after');
}, },
/** /**
@ -274,7 +276,7 @@ statusBar.setStatus({
setStatus : function(o) { setStatus : function(o) {
o = o || {}; o = o || {};
if(typeof o == 'string'){ if (Ext.isString(o)) {
o = {text:o}; o = {text:o};
} }
if (o.text !== undefined) { if (o.text !== undefined) {
@ -289,21 +291,22 @@ statusBar.setStatus({
wait = this.autoClear, wait = this.autoClear,
defaults = {useDefaults: true, anim: true}; defaults = {useDefaults: true, anim: true};
if(typeof c == 'object'){ if (Ext.isObject(c)) {
c = Ext.applyIf(c, defaults); c = Ext.applyIf(c, defaults);
if (c.wait) { if (c.wait) {
wait = c.wait; wait = c.wait;
} }
}else if(typeof c == 'number'){ } else if (Ext.isNumber(c)) {
wait = c; wait = c;
c = defaults; c = defaults;
}else if(typeof c == 'boolean'){ } else if (Ext.isBoolean(c)) {
c = defaults; c = defaults;
} }
c.threadId = this.activeThreadId; c.threadId = this.activeThreadId;
this.clearStatus.defer(wait, this, [c]); Ext.defer(this.clearStatus, wait, this, [c]);
} }
this.doLayout();
return this; return this;
}, },
@ -332,8 +335,8 @@ statusBar.setStatus({
iconCls = o.useDefaults ? (this.defaultIconCls ? this.defaultIconCls : '') : ''; iconCls = o.useDefaults ? (this.defaultIconCls ? this.defaultIconCls : '') : '';
if (o.anim) { if (o.anim) {
// animate the statusEl Ext.Element // animate the statusEl Ext.core.Element
this.statusEl.el.fadeOut({ this.statusEl.el.puff({
remove: false, remove: false,
useDisplay: true, useDisplay: true,
scope: this, scope: this,
@ -355,6 +358,7 @@ statusBar.setStatus({
}); });
this.statusEl.show(); this.statusEl.show();
} }
this.doLayout();
return this; return this;
}, },
@ -392,11 +396,11 @@ statusBar.setStatus({
if (this.rendered) { if (this.rendered) {
if (this.currIconCls) { if (this.currIconCls) {
this.statusEl.removeClass(this.currIconCls); this.statusEl.removeCls(this.currIconCls);
this.currIconCls = null; this.currIconCls = null;
} }
if (cls.length > 0) { if (cls.length > 0) {
this.statusEl.addClass(cls); this.statusEl.addCls(cls);
this.currIconCls = cls; this.currIconCls = cls;
} }
} else { } else {
@ -416,7 +420,7 @@ statusBar.setStatus({
* @return {Ext.ux.StatusBar} this * @return {Ext.ux.StatusBar} this
*/ */
showBusy : function(o){ showBusy : function(o){
if(typeof o == 'string'){ if (Ext.isString(o)) {
o = { text: o }; o = { text: o };
} }
o = Ext.applyIf(o || {}, { o = Ext.applyIf(o || {}, {
@ -426,4 +430,4 @@ statusBar.setStatus({
return this.setStatus(o); return this.setStatus(o);
} }
}); });
Ext.reg('statusbar', Ext.ux.StatusBar);

View File

@ -1,182 +0,0 @@
/*!
* Ext JS Library 3.1.0
* Copyright(c) 2006-2009 Ext JS, LLC
* licensing@extjs.com
* http://www.extjs.com/license
*/
Ext.ns('Ext.ux.form');
/**
* @class Ext.ux.form.FileUploadField
* @extends Ext.form.TextField
* Creates a file upload field.
* @xtype fileuploadfield
*/
Ext.ux.form.FileUploadField = Ext.extend(Ext.form.TextField, {
/**
* @cfg {String} buttonText The button text to display on the upload button (defaults to
* 'Browse...'). Note that if you supply a value for {@link #buttonCfg}, the buttonCfg.text
* value will be used instead if available.
*/
buttonText: 'Browse...',
/**
* @cfg {Boolean} buttonOnly True to display the file upload field as a button with no visible
* text field (defaults to false). If true, all inherited TextField members will still be available.
*/
buttonOnly: false,
/**
* @cfg {Number} buttonOffset The number of pixels of space reserved between the button and the text field
* (defaults to 3). Note that this only applies if {@link #buttonOnly} = false.
*/
buttonOffset: 3,
/**
* @cfg {Object} buttonCfg A standard {@link Ext.Button} config object.
*/
// private
readOnly: true,
/**
* @hide
* @method autoSize
*/
autoSize: Ext.emptyFn,
// private
initComponent: function(){
Ext.ux.form.FileUploadField.superclass.initComponent.call(this);
this.addEvents(
/**
* @event fileselected
* Fires when the underlying file input field's value has changed from the user
* selecting a new file from the system file selection dialog.
* @param {Ext.ux.form.FileUploadField} this
* @param {String} value The file value returned by the underlying file input field
*/
'fileselected'
);
},
// private
onRender : function(ct, position){
Ext.ux.form.FileUploadField.superclass.onRender.call(this, ct, position);
this.wrap = this.el.wrap({cls:'x-form-field-wrap x-form-file-wrap'});
this.el.addClass('x-form-file-text');
this.el.dom.removeAttribute('name');
this.createFileInput();
var btnCfg = Ext.applyIf(this.buttonCfg || {}, {
text: this.buttonText
});
this.button = new Ext.Button(Ext.apply(btnCfg, {
renderTo: this.wrap,
cls: 'x-form-file-btn' + (btnCfg.iconCls ? ' x-btn-icon' : '')
}));
if(this.buttonOnly){
this.el.hide();
this.wrap.setWidth(this.button.getEl().getWidth());
}
this.bindListeners();
this.resizeEl = this.positionEl = this.wrap;
},
bindListeners: function(){
this.fileInput.on({
scope: this,
mouseenter: function() {
this.button.addClass(['x-btn-over','x-btn-focus'])
},
mouseleave: function(){
this.button.removeClass(['x-btn-over','x-btn-focus','x-btn-click'])
},
mousedown: function(){
this.button.addClass('x-btn-click')
},
mouseup: function(){
this.button.removeClass(['x-btn-over','x-btn-focus','x-btn-click'])
},
change: function(){
var v = this.fileInput.dom.value;
this.setValue(v);
this.fireEvent('fileselected', this, v);
}
});
},
createFileInput : function() {
this.fileInput = this.wrap.createChild({
id: this.getFileInputId(),
name: this.name||this.getId(),
cls: 'x-form-file',
tag: 'input',
type: 'file',
size: 1
});
},
reset : function(){
this.fileInput.remove();
this.createFileInput();
this.bindListeners();
Ext.ux.form.FileUploadField.superclass.reset.call(this);
},
// private
getFileInputId: function(){
return this.id + '-file';
},
// private
onResize : function(w, h){
Ext.ux.form.FileUploadField.superclass.onResize.call(this, w, h);
this.wrap.setWidth(w);
if(!this.buttonOnly){
var w = this.wrap.getWidth() - this.button.getEl().getWidth() - this.buttonOffset;
this.el.setWidth(w);
}
},
// private
onDestroy: function(){
Ext.ux.form.FileUploadField.superclass.onDestroy.call(this);
Ext.destroy(this.fileInput, this.button, this.wrap);
},
onDisable: function(){
Ext.ux.form.FileUploadField.superclass.onDisable.call(this);
this.doDisable(true);
},
onEnable: function(){
Ext.ux.form.FileUploadField.superclass.onEnable.call(this);
this.doDisable(false);
},
// private
doDisable: function(disabled){
this.fileInput.dom.disabled = disabled;
this.button.setDisabled(disabled);
},
// private
preFocus : Ext.emptyFn,
// private
alignErrorIcon : function(){
this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
}
});
Ext.reg('fileuploadfield', Ext.ux.form.FileUploadField);
// backwards compat
Ext.form.FileUploadField = Ext.ux.form.FileUploadField;

View File

@ -1,61 +0,0 @@
/*!
* Ext JS Library 3.1.0
* Copyright(c) 2006-2009 Ext JS, LLC
* licensing@extjs.com
* http://www.extjs.com/license
*/
Ext.ns('Ext.ux.form');
/**
* @class Ext.ux.form.SpinnerField
* @extends Ext.form.NumberField
* Creates a field utilizing Ext.ux.Spinner
* @xtype spinnerfield
*/
Ext.ux.form.SpinnerField = Ext.extend(Ext.form.NumberField, {
actionMode: 'wrap',
deferHeight: true,
autoSize: Ext.emptyFn,
onBlur: Ext.emptyFn,
adjustSize: Ext.BoxComponent.prototype.adjustSize,
constructor: function(config) {
var spinnerConfig = Ext.copyTo({}, config, 'incrementValue,alternateIncrementValue,accelerate,defaultValue,triggerClass,splitterClass');
var spl = this.spinner = new Ext.ux.Spinner(spinnerConfig);
var plugins = config.plugins
? (Ext.isArray(config.plugins)
? config.plugins.push(spl)
: [config.plugins, spl])
: spl;
Ext.ux.form.SpinnerField.superclass.constructor.call(this, Ext.apply(config, {plugins: plugins}));
},
// private
getResizeEl: function(){
return this.wrap;
},
// private
getPositionEl: function(){
return this.wrap;
},
// private
alignErrorIcon: function(){
if (this.wrap) {
this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
}
},
validateBlur: function(){
return true;
}
});
Ext.reg('spinnerfield', Ext.ux.form.SpinnerField);
//backwards compat
Ext.form.SpinnerField = Ext.ux.form.SpinnerField;

View File

@ -29,12 +29,20 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.ns('Ext.ux.form');
/** /**
* Ext.ux.form.SpinnerGroup class
* *
* @author Damien Churchill
* @version v0.1
*
* @class Ext.ux.form.SpinnerGroup
* @extends Ext.form.CheckboxGroup
*/ */
Ext.ux.form.SpinnerGroup = Ext.extend(Ext.form.CheckboxGroup, { Ext.define('Ext.ux.form.SpinnerGroup', {
extend: 'Ext.form.CheckboxGroup',
alias: 'widget.spinnergroup',
// private // private
defaultType: 'spinnerfield', defaultType: 'spinnerfield',
@ -169,7 +177,7 @@ Ext.ux.form.SpinnerGroup = Ext.extend(Ext.form.CheckboxGroup, {
} }
} }
Ext.ux.form.SpinnerGroup.superclass.onRender.call(this, ct, position); this.callParent(arguments);
}, },
onFieldChange: function(spinner) { onFieldChange: function(spinner) {
@ -216,4 +224,3 @@ Ext.ux.form.SpinnerGroup = Ext.extend(Ext.form.CheckboxGroup, {
} }
} }
}); });
Ext.reg('spinnergroup', Ext.ux.form.SpinnerGroup);

View File

@ -1,7 +1,7 @@
/*! /*!
* Ext.ux.form.ToggleField.js * Ext.ux.form.ToggleField.js
* *
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2009-2011 <damoxc@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,7 +29,6 @@
* this exception statement from your version. If you delete this exception * this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here. * statement from all source files in the program, then also delete it here.
*/ */
Ext.namespace("Ext.ux.form");
/** /**
* Ext.ux.form.ToggleField class * Ext.ux.form.ToggleField class
@ -40,12 +39,15 @@ Ext.namespace("Ext.ux.form");
* @class Ext.ux.form.ToggleField * @class Ext.ux.form.ToggleField
* @extends Ext.form.TriggerField * @extends Ext.form.TriggerField
*/ */
Ext.ux.form.ToggleField = Ext.extend(Ext.form.Field, { Ext.define('Ext.ux.form.ToggleField', {
extend: 'Ext.form.Field',
alias: 'widget.togglefield',
cls: 'x-toggle-field', cls: 'x-toggle-field',
initComponent: function() { initComponent: function() {
Ext.ux.form.ToggleField.superclass.initComponent.call(this); this.callParent(arguments);
this.toggle = new Ext.form.Checkbox(); this.toggle = new Ext.form.Checkbox();
this.toggle.on('check', this.onToggleCheck, this); this.toggle.on('check', this.onToggleCheck, this);
@ -75,7 +77,7 @@ Ext.ux.form.ToggleField = Ext.extend(Ext.form.Field, {
this.toggle.getEl().parent().setStyle('padding-right', '10px'); this.toggle.getEl().parent().setStyle('padding-right', '10px');
} }
Ext.ux.form.ToggleField.superclass.onRender.call(this, ct, position); this.callParent(arguments);
}, },
// private // private
@ -92,4 +94,3 @@ Ext.ux.form.ToggleField = Ext.extend(Ext.form.Field, {
this.input.setDisabled(!checked); this.input.setDisabled(!checked);
} }
}); });
Ext.reg('togglefield', Ext.ux.form.ToggleField);

View File

@ -1,219 +0,0 @@
/*!
* Ext JS Library 3.1.0
* Copyright(c) 2006-2009 Ext JS, LLC
* licensing@extjs.com
* http://www.extjs.com/license
*/
Ext.ns('Ext.ux.grid');
/**
* @class Ext.ux.grid.BufferView
* @extends Ext.grid.GridView
* A custom GridView which renders rows on an as-needed basis.
*/
Ext.ux.grid.BufferView = Ext.extend(Ext.grid.GridView, {
/**
* @cfg {Number} rowHeight
* The height of a row in the grid.
*/
rowHeight: 19,
/**
* @cfg {Number} borderHeight
* The combined height of border-top and border-bottom of a row.
*/
borderHeight: 2,
/**
* @cfg {Boolean/Number} scrollDelay
* The number of milliseconds before rendering rows out of the visible
* viewing area. Defaults to 100. Rows will render immediately with a config
* of false.
*/
scrollDelay: 100,
/**
* @cfg {Number} cacheSize
* The number of rows to look forward and backwards from the currently viewable
* area. The cache applies only to rows that have been rendered already.
*/
cacheSize: 20,
/**
* @cfg {Number} cleanDelay
* The number of milliseconds to buffer cleaning of extra rows not in the
* cache.
*/
cleanDelay: 500,
initTemplates : function(){
Ext.ux.grid.BufferView.superclass.initTemplates.call(this);
var ts = this.templates;
// empty div to act as a place holder for a row
ts.rowHolder = new Ext.Template(
'<div class="x-grid3-row {alt}" style="{tstyle}"></div>'
);
ts.rowHolder.disableFormats = true;
ts.rowHolder.compile();
ts.rowBody = new Ext.Template(
'<table class="x-grid3-row-table" border="0" cellspacing="0" cellpadding="0" style="{tstyle}">',
'<tbody><tr>{cells}</tr>',
(this.enableRowBody ? '<tr class="x-grid3-row-body-tr" style="{bodyStyle}"><td colspan="{cols}" class="x-grid3-body-cell" tabIndex="0" hidefocus="on"><div class="x-grid3-row-body">{body}</div></td></tr>' : ''),
'</tbody></table>'
);
ts.rowBody.disableFormats = true;
ts.rowBody.compile();
},
getStyleRowHeight : function(){
return Ext.isBorderBox ? (this.rowHeight + this.borderHeight) : this.rowHeight;
},
getCalculatedRowHeight : function(){
return this.rowHeight + this.borderHeight;
},
getVisibleRowCount : function(){
var rh = this.getCalculatedRowHeight();
var visibleHeight = this.scroller.dom.clientHeight;
return (visibleHeight < 1) ? 0 : Math.ceil(visibleHeight / rh);
},
getVisibleRows: function(){
var count = this.getVisibleRowCount();
var sc = this.scroller.dom.scrollTop;
var start = (sc == 0 ? 0 : Math.floor(sc/this.getCalculatedRowHeight())-1);
return {
first: Math.max(start, 0),
last: Math.min(start + count + 2, this.ds.getCount()-1)
};
},
doRender : function(cs, rs, ds, startRow, colCount, stripe, onlyBody){
var ts = this.templates, ct = ts.cell, rt = ts.row, rb = ts.rowBody, last = colCount-1;
var rh = this.getStyleRowHeight();
var vr = this.getVisibleRows();
var tstyle = 'width:'+this.getTotalWidth()+';height:'+rh+'px;';
// buffers
var buf = [], cb, c, p = {}, rp = {tstyle: tstyle}, r;
for (var j = 0, len = rs.length; j < len; j++) {
r = rs[j]; cb = [];
var rowIndex = (j+startRow);
var visible = rowIndex >= vr.first && rowIndex <= vr.last;
if (visible) {
for (var i = 0; i < colCount; i++) {
c = cs[i];
p.id = c.id;
p.css = i == 0 ? 'x-grid3-cell-first ' : (i == last ? 'x-grid3-cell-last ' : '');
p.attr = p.cellAttr = "";
p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
p.style = c.style;
if (p.value == undefined || p.value === "") {
p.value = "&#160;";
}
if (r.dirty && typeof r.modified[c.name] !== 'undefined') {
p.css += ' x-grid3-dirty-cell';
}
cb[cb.length] = ct.apply(p);
}
}
var alt = [];
if(stripe && ((rowIndex+1) % 2 == 0)){
alt[0] = "x-grid3-row-alt";
}
if(r.dirty){
alt[1] = " x-grid3-dirty-row";
}
rp.cols = colCount;
if(this.getRowClass){
alt[2] = this.getRowClass(r, rowIndex, rp, ds);
}
rp.alt = alt.join(" ");
rp.cells = cb.join("");
buf[buf.length] = !visible ? ts.rowHolder.apply(rp) : (onlyBody ? rb.apply(rp) : rt.apply(rp));
}
return buf.join("");
},
isRowRendered: function(index){
var row = this.getRow(index);
return row && row.childNodes.length > 0;
},
syncScroll: function(){
Ext.ux.grid.BufferView.superclass.syncScroll.apply(this, arguments);
this.update();
},
// a (optionally) buffered method to update contents of gridview
update: function(){
if (this.scrollDelay) {
if (!this.renderTask) {
this.renderTask = new Ext.util.DelayedTask(this.doUpdate, this);
}
this.renderTask.delay(this.scrollDelay);
}else{
this.doUpdate();
}
},
onRemove : function(ds, record, index, isUpdate){
Ext.ux.grid.BufferView.superclass.onRemove.apply(this, arguments);
if(isUpdate !== true){
this.update();
}
},
doUpdate: function(){
if (this.getVisibleRowCount() > 0) {
var g = this.grid, cm = g.colModel, ds = g.store;
var cs = this.getColumnData();
var vr = this.getVisibleRows();
for (var i = vr.first; i <= vr.last; i++) {
// if row is NOT rendered and is visible, render it
if(!this.isRowRendered(i)){
var html = this.doRender(cs, [ds.getAt(i)], ds, i, cm.getColumnCount(), g.stripeRows, true);
this.getRow(i).innerHTML = html;
}
}
this.clean();
}
},
// a buffered method to clean rows
clean : function(){
if(!this.cleanTask){
this.cleanTask = new Ext.util.DelayedTask(this.doClean, this);
}
this.cleanTask.delay(this.cleanDelay);
},
doClean: function(){
if (this.getVisibleRowCount() > 0) {
var vr = this.getVisibleRows();
vr.first -= this.cacheSize;
vr.last += this.cacheSize;
var i = 0, rows = this.getRows();
// if first is less than 0, all rows have been rendered
// so lets clean the end...
if(vr.first <= 0){
i = vr.last + 1;
}
for(var len = this.ds.getCount(); i < len; i++){
// if current row is outside of first and last and
// has content, update the innerHTML to nothing
if ((i < vr.first || i > vr.last) && rows[i].innerHTML) {
rows[i].innerHTML = '';
}
}
}
},
layout: function(){
Ext.ux.grid.BufferView.superclass.layout.call(this);
this.update();
}
});

View File

@ -1,92 +0,0 @@
/*!
* Ext.ux.tree.MultiSelectionModelFix.js
*
* Copyright (c) Damien Churchill 2009-2010 <damoxc@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, write to:
* The Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the OpenSSL
* library.
* You must obey the GNU General Public License in all respects for all of
* the code used other than OpenSSL. If you modify file(s) with this
* exception, you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete
* this exception statement from your version. If you delete this exception
* statement from all source files in the program, then also delete it here.
*/
/**
* This enhances the MSM to allow for shift selecting in tree grids etc.
* @author Damien Churchill <damoxc@gmail.com>
*/
Ext.override(Ext.tree.MultiSelectionModel, {
onNodeClick: function (node, e) {
if (e.ctrlKey && this.isSelected(node)) {
this.unselect(node);
} else if (e.shiftKey && !this.isSelected(node)) {
var parentNode = node.parentNode;
// We can only shift select files in the same node
if (this.lastSelNode.parentNode.id != parentNode.id) return;
// Get the node indexes
var fi = parentNode.indexOf(node),
li = parentNode.indexOf(this.lastSelNode);
// Select the last clicked node and wipe old selections
this.select(this.lastSelNode, e, false, true);
// Swap the values if required
if (fi > li) {
fi = fi + li, li = fi - li, fi = fi - li;
}
// Select all the nodes
parentNode.eachChild(function(n) {
var i = parentNode.indexOf(n);
if (fi < i && i < li) {
this.select(n, e, true, true);
}
}, this);
// Select the clicked node
this.select(node, e, true);
} else {
this.select(node, e, e.ctrlKey);
}
},
select: function(node, e, keepExisting, suppressEvent) {
if(keepExisting !== true){
this.clearSelections(true);
}
if(this.isSelected(node)){
this.lastSelNode = node;
return node;
}
this.selNodes.push(node);
this.selMap[node.id] = node;
this.lastSelNode = node;
node.ui.onSelectedChange(true);
if (suppressEvent !== true) {
this.fireEvent('selectionchange', this, this.selNodes);
}
return node;
}
})

View File

@ -1,409 +0,0 @@
/*!
* Ext JS Library 3.1.0
* Copyright(c) 2006-2009 Ext JS, LLC
* licensing@extjs.com
* http://www.extjs.com/license
*/
Ext.ns('Ext.ux.tree');
/**
* @class Ext.ux.tree.TreeGrid
* @extends Ext.tree.TreePanel
*
* @xtype treegrid
*/
Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
rootVisible : false,
useArrows : true,
lines : false,
borderWidth : Ext.isBorderBox ? 0 : 2, // the combined left/right border for each cell
cls : 'x-treegrid',
columnResize : true,
enableSort : true,
reserveScrollOffset : true,
enableHdMenu : true,
columnsText : 'Columns',
initComponent : function() {
if(!this.root) {
this.root = new Ext.tree.AsyncTreeNode({text: 'Root'});
}
// initialize the loader
var l = this.loader;
if(!l){
l = new Ext.ux.tree.TreeGridLoader({
dataUrl: this.dataUrl,
requestMethod: this.requestMethod,
store: this.store
});
}else if(Ext.isObject(l) && !l.load){
l = new Ext.ux.tree.TreeGridLoader(l);
}
else if(l) {
l.createNode = function(attr) {
if (!attr.uiProvider) {
attr.uiProvider = Ext.ux.tree.TreeGridNodeUI;
}
return Ext.tree.TreeLoader.prototype.createNode.call(this, attr);
}
}
this.loader = l;
Ext.ux.tree.TreeGrid.superclass.initComponent.call(this);
this.initColumns();
if(this.enableSort) {
this.treeGridSorter = new Ext.ux.tree.TreeGridSorter(this, this.enableSort);
}
if(this.columnResize){
this.colResizer = new Ext.tree.ColumnResizer(this.columnResize);
this.colResizer.init(this);
}
var c = this.columns;
if(!this.internalTpl){
this.internalTpl = new Ext.XTemplate(
'<div class="x-grid3-header">',
'<div class="x-treegrid-header-inner">',
'<div class="x-grid3-header-offset">',
'<table cellspacing="0" cellpadding="0" border="0"><colgroup><tpl for="columns"><col /></tpl></colgroup>',
'<thead><tr class="x-grid3-hd-row">',
'<tpl for="columns">',
'<td class="x-grid3-hd x-grid3-cell x-treegrid-hd" style="text-align: {align};" id="', this.id, '-xlhd-{#}">',
'<div class="x-grid3-hd-inner x-treegrid-hd-inner" unselectable="on">',
this.enableHdMenu ? '<a class="x-grid3-hd-btn" href="#"></a>' : '',
'{header}<img class="x-grid3-sort-icon" src="', Ext.BLANK_IMAGE_URL, '" />',
'</div>',
'</td></tpl>',
'</tr></thead>',
'</div></table>',
'</div></div>',
'</div>',
'<div class="x-treegrid-root-node">',
'<table class="x-treegrid-root-table" cellpadding="0" cellspacing="0" style="table-layout: fixed;"></table>',
'</div>'
);
}
if(!this.colgroupTpl) {
this.colgroupTpl = new Ext.XTemplate(
'<colgroup><tpl for="columns"><col style="width: {width}px"/></tpl></colgroup>'
);
}
},
initColumns : function() {
var cs = this.columns,
len = cs.length,
columns = [],
i, c;
for(i = 0; i < len; i++){
c = cs[i];
if(!c.isColumn) {
c.xtype = c.xtype ? (/^tg/.test(c.xtype) ? c.xtype : 'tg' + c.xtype) : 'tgcolumn';
c = Ext.create(c);
}
c.init(this);
columns.push(c);
if(this.enableSort !== false && c.sortable !== false) {
c.sortable = true;
this.enableSort = true;
}
}
this.columns = columns;
},
onRender : function(){
Ext.tree.TreePanel.superclass.onRender.apply(this, arguments);
this.el.addClass('x-treegrid');
this.outerCt = this.body.createChild({
cls:'x-tree-root-ct x-treegrid-ct ' + (this.useArrows ? 'x-tree-arrows' : this.lines ? 'x-tree-lines' : 'x-tree-no-lines')
});
this.internalTpl.overwrite(this.outerCt, {columns: this.columns});
this.mainHd = Ext.get(this.outerCt.dom.firstChild);
this.innerHd = Ext.get(this.mainHd.dom.firstChild);
this.innerBody = Ext.get(this.outerCt.dom.lastChild);
this.innerCt = Ext.get(this.innerBody.dom.firstChild);
this.colgroupTpl.insertFirst(this.innerCt, {columns: this.columns});
if(this.hideHeaders){
this.header.dom.style.display = 'none';
}
else if(this.enableHdMenu !== false){
this.hmenu = new Ext.menu.Menu({id: this.id + '-hctx'});
if(this.enableColumnHide !== false){
this.colMenu = new Ext.menu.Menu({id: this.id + '-hcols-menu'});
this.colMenu.on({
scope: this,
beforeshow: this.beforeColMenuShow,
itemclick: this.handleHdMenuClick
});
this.hmenu.add({
itemId:'columns',
hideOnClick: false,
text: this.columnsText,
menu: this.colMenu,
iconCls: 'x-cols-icon'
});
}
this.hmenu.on('itemclick', this.handleHdMenuClick, this);
}
},
setRootNode : function(node){
node.attributes.uiProvider = Ext.ux.tree.TreeGridRootNodeUI;
node = Ext.ux.tree.TreeGrid.superclass.setRootNode.call(this, node);
if(this.innerCt) {
this.colgroupTpl.insertFirst(this.innerCt, {columns: this.columns});
}
return node;
},
initEvents : function() {
Ext.ux.tree.TreeGrid.superclass.initEvents.apply(this, arguments);
this.mon(this.innerBody, 'scroll', this.syncScroll, this);
this.mon(this.innerHd, 'click', this.handleHdDown, this);
this.mon(this.mainHd, {
scope: this,
mouseover: this.handleHdOver,
mouseout: this.handleHdOut
});
},
onResize : function(w, h) {
Ext.ux.tree.TreeGrid.superclass.onResize.apply(this, arguments);
var bd = this.innerBody.dom;
var hd = this.innerHd.dom;
if(!bd){
return;
}
if(Ext.isNumber(h)){
bd.style.height = this.body.getHeight(true) - hd.offsetHeight + 'px';
}
if(Ext.isNumber(w)){
var sw = Ext.num(this.scrollOffset, Ext.getScrollBarWidth());
if(this.reserveScrollOffset || ((bd.offsetWidth - bd.clientWidth) > 10)){
this.setScrollOffset(sw);
}else{
var me = this;
setTimeout(function(){
me.setScrollOffset(bd.offsetWidth - bd.clientWidth > 10 ? sw : 0);
}, 10);
}
}
},
updateColumnWidths : function() {
var cols = this.columns,
colCount = cols.length,
groups = this.outerCt.query('colgroup'),
groupCount = groups.length,
c, g, i, j;
for(i = 0; i<colCount; i++) {
c = cols[i];
for(j = 0; j<groupCount; j++) {
g = groups[j];
g.childNodes[i].style.width = (c.hidden ? 0 : c.width) + 'px';
}
}
for(i = 0, groups = this.innerHd.query('td'), len = groups.length; i<len; i++) {
c = Ext.fly(groups[i]);
if(cols[i] && cols[i].hidden) {
c.addClass('x-treegrid-hd-hidden');
}
else {
c.removeClass('x-treegrid-hd-hidden');
}
}
var tcw = this.getTotalColumnWidth();
Ext.fly(this.innerHd.dom.firstChild).setWidth(tcw + (this.scrollOffset || 0));
this.outerCt.select('table').setWidth(tcw);
this.syncHeaderScroll();
},
getVisibleColumns : function() {
var columns = [],
cs = this.columns,
len = cs.length,
i;
for(i = 0; i<len; i++) {
if(!cs[i].hidden) {
columns.push(cs[i]);
}
}
return columns;
},
getTotalColumnWidth : function() {
var total = 0;
for(var i = 0, cs = this.getVisibleColumns(), len = cs.length; i<len; i++) {
total += cs[i].width;
}
return total;
},
setScrollOffset : function(scrollOffset) {
this.scrollOffset = scrollOffset;
this.updateColumnWidths();
},
// private
handleHdDown : function(e, t){
var hd = e.getTarget('.x-treegrid-hd');
if(hd && Ext.fly(t).hasClass('x-grid3-hd-btn')){
var ms = this.hmenu.items,
cs = this.columns,
index = this.findHeaderIndex(hd),
c = cs[index],
sort = c.sortable;
e.stopEvent();
Ext.fly(hd).addClass('x-grid3-hd-menu-open');
this.hdCtxIndex = index;
this.fireEvent('headerbuttonclick', ms, c, hd, index);
this.hmenu.on('hide', function(){
Ext.fly(hd).removeClass('x-grid3-hd-menu-open');
}, this, {single:true});
this.hmenu.show(t, 'tl-bl?');
}
else if(hd) {
var index = this.findHeaderIndex(hd);
this.fireEvent('headerclick', this.columns[index], hd, index);
}
},
// private
handleHdOver : function(e, t){
var hd = e.getTarget('.x-treegrid-hd');
if(hd && !this.headersDisabled){
index = this.findHeaderIndex(hd);
this.activeHdRef = t;
this.activeHdIndex = index;
var el = Ext.get(hd);
this.activeHdRegion = el.getRegion();
el.addClass('x-grid3-hd-over');
this.activeHdBtn = el.child('.x-grid3-hd-btn');
if(this.activeHdBtn){
this.activeHdBtn.dom.style.height = (hd.firstChild.offsetHeight-1)+'px';
}
}
},
// private
handleHdOut : function(e, t){
var hd = e.getTarget('.x-treegrid-hd');
if(hd && (!Ext.isIE || !e.within(hd, true))){
this.activeHdRef = null;
Ext.fly(hd).removeClass('x-grid3-hd-over');
hd.style.cursor = '';
}
},
findHeaderIndex : function(hd){
hd = hd.dom || hd;
var cs = hd.parentNode.childNodes;
for(var i = 0, c; c = cs[i]; i++){
if(c == hd){
return i;
}
}
return -1;
},
// private
beforeColMenuShow : function(){
var cols = this.columns,
colCount = cols.length,
i, c;
this.colMenu.removeAll();
for(i = 1; i < colCount; i++){
c = cols[i];
if(c.hideable !== false){
this.colMenu.add(new Ext.menu.CheckItem({
itemId: 'col-' + i,
text: c.header,
checked: !c.hidden,
hideOnClick:false,
disabled: c.hideable === false
}));
}
}
},
// private
handleHdMenuClick : function(item){
var index = this.hdCtxIndex,
id = item.getItemId();
if(this.fireEvent('headermenuclick', this.columns[index], id, index) !== false) {
index = id.substr(4);
if(index > 0 && this.columns[index]) {
this.setColumnVisible(index, !item.checked);
}
}
return true;
},
setColumnVisible : function(index, visible) {
this.columns[index].hidden = !visible;
this.updateColumnWidths();
},
/**
* Scrolls the grid to the top
*/
scrollToTop : function(){
this.innerBody.dom.scrollTop = 0;
this.innerBody.dom.scrollLeft = 0;
},
// private
syncScroll : function(){
this.syncHeaderScroll();
var mb = this.innerBody.dom;
this.fireEvent('bodyscroll', mb.scrollLeft, mb.scrollTop);
},
// private
syncHeaderScroll : function(){
var mb = this.innerBody.dom;
this.innerHd.dom.scrollLeft = mb.scrollLeft;
this.innerHd.dom.scrollLeft = mb.scrollLeft; // second time for IE (1/2 time first fails, other browsers ignore)
},
registerNode : function(n) {
Ext.ux.tree.TreeGrid.superclass.registerNode.call(this, n);
if(!n.uiProvider && !n.isRoot && !n.ui.isTreeGridNodeUI) {
n.ui = new Ext.ux.tree.TreeGridNodeUI(n);
}
}
});
Ext.reg('treegrid', Ext.ux.tree.TreeGrid);

View File

@ -1,117 +0,0 @@
/*!
* Ext JS Library 3.1.0
* Copyright(c) 2006-2009 Ext JS, LLC
* licensing@extjs.com
* http://www.extjs.com/license
*/
/**
* @class Ext.tree.ColumnResizer
* @extends Ext.util.Observable
*/
Ext.tree.ColumnResizer = Ext.extend(Ext.util.Observable, {
/**
* @cfg {Number} minWidth The minimum width the column can be dragged to.
* Defaults to <tt>14</tt>.
*/
minWidth: 14,
constructor: function(config){
Ext.apply(this, config);
Ext.tree.ColumnResizer.superclass.constructor.call(this);
},
init : function(tree){
this.tree = tree;
tree.on('render', this.initEvents, this);
},
initEvents : function(tree){
tree.mon(tree.innerHd, 'mousemove', this.handleHdMove, this);
this.tracker = new Ext.dd.DragTracker({
onBeforeStart: this.onBeforeStart.createDelegate(this),
onStart: this.onStart.createDelegate(this),
onDrag: this.onDrag.createDelegate(this),
onEnd: this.onEnd.createDelegate(this),
tolerance: 3,
autoStart: 300
});
this.tracker.initEl(tree.innerHd);
tree.on('beforedestroy', this.tracker.destroy, this.tracker);
},
handleHdMove : function(e, t){
var hw = 5,
x = e.getPageX(),
hd = e.getTarget('.x-treegrid-hd', 3, true);
if(hd){
var r = hd.getRegion(),
ss = hd.dom.style,
pn = hd.dom.parentNode;
if(x - r.left <= hw && hd.dom !== pn.firstChild) {
var ps = hd.dom.previousSibling;
while(ps && Ext.fly(ps).hasClass('x-treegrid-hd-hidden')) {
ps = ps.previousSibling;
}
if(ps) {
this.activeHd = Ext.get(ps);
ss.cursor = Ext.isWebKit ? 'e-resize' : 'col-resize';
}
} else if(r.right - x <= hw) {
var ns = hd.dom;
while(ns && Ext.fly(ns).hasClass('x-treegrid-hd-hidden')) {
ns = ns.previousSibling;
}
if(ns) {
this.activeHd = Ext.get(ns);
ss.cursor = Ext.isWebKit ? 'w-resize' : 'col-resize';
}
} else{
delete this.activeHd;
ss.cursor = '';
}
}
},
onBeforeStart : function(e){
this.dragHd = this.activeHd;
return !!this.dragHd;
},
onStart : function(e){
this.tree.headersDisabled = true;
this.proxy = this.tree.body.createChild({cls:'x-treegrid-resizer'});
this.proxy.setHeight(this.tree.body.getHeight());
var x = this.tracker.getXY()[0];
this.hdX = this.dragHd.getX();
this.hdIndex = this.tree.findHeaderIndex(this.dragHd);
this.proxy.setX(this.hdX);
this.proxy.setWidth(x-this.hdX);
this.maxWidth = this.tree.outerCt.getWidth() - this.tree.innerBody.translatePoints(this.hdX).left;
},
onDrag : function(e){
var cursorX = this.tracker.getXY()[0];
this.proxy.setWidth((cursorX-this.hdX).constrain(this.minWidth, this.maxWidth));
},
onEnd : function(e){
var nw = this.proxy.getWidth(),
tree = this.tree;
this.proxy.remove();
delete this.dragHd;
tree.columns[this.hdIndex].width = nw;
tree.updateColumnWidths();
setTimeout(function(){
tree.headersDisabled = false;
}, 100);
}
});

View File

@ -1,45 +0,0 @@
/*!
* Ext JS Library 3.1.0
* Copyright(c) 2006-2009 Ext JS, LLC
* licensing@extjs.com
* http://www.extjs.com/license
*/
(function() {
Ext.override(Ext.list.Column, {
init : function() {
if(!this.type){
this.type = "auto";
}
var st = Ext.data.SortTypes;
// named sortTypes are supported, here we look them up
if(typeof this.sortType == "string"){
this.sortType = st[this.sortType];
}
// set default sortType for strings and dates
if(!this.sortType){
switch(this.type){
case "string":
this.sortType = st.asUCString;
break;
case "date":
this.sortType = st.asDate;
break;
default:
this.sortType = st.none;
}
}
}
});
Ext.tree.Column = Ext.extend(Ext.list.Column, {});
Ext.tree.NumberColumn = Ext.extend(Ext.list.NumberColumn, {});
Ext.tree.DateColumn = Ext.extend(Ext.list.DateColumn, {});
Ext.tree.BooleanColumn = Ext.extend(Ext.list.BooleanColumn, {});
Ext.reg('tgcolumn', Ext.tree.Column);
Ext.reg('tgnumbercolumn', Ext.tree.NumberColumn);
Ext.reg('tgdatecolumn', Ext.tree.DateColumn);
Ext.reg('tgbooleancolumn', Ext.tree.BooleanColumn);
})();

View File

@ -1,18 +0,0 @@
/*!
* Ext JS Library 3.1.0
* Copyright(c) 2006-2009 Ext JS, LLC
* licensing@extjs.com
* http://www.extjs.com/license
*/
/**
* @class Ext.ux.tree.TreeGridLoader
* @extends Ext.tree.TreeLoader
*/
Ext.ux.tree.TreeGridLoader = Ext.extend(Ext.tree.TreeLoader, {
createNode : function(attr) {
if (!attr.uiProvider) {
attr.uiProvider = Ext.ux.tree.TreeGridNodeUI;
}
return Ext.tree.TreeLoader.prototype.createNode.call(this, attr);
}
});

View File

@ -1,107 +0,0 @@
/*!
* Ext JS Library 3.1.0
* Copyright(c) 2006-2009 Ext JS, LLC
* licensing@extjs.com
* http://www.extjs.com/license
*/
/**
* @class Ext.ux.tree.TreeGridNodeUI
* @extends Ext.tree.TreeNodeUI
*/
Ext.ux.tree.TreeGridNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
isTreeGridNodeUI: true,
renderElements : function(n, a, targetNode, bulkRender){
var t = n.getOwnerTree(),
cols = t.columns,
c = cols[0],
i, buf, len;
this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
buf = [
'<tbody class="x-tree-node">',
'<tr ext:tree-node-id="', n.id ,'" class="x-tree-node-el ', a.cls, '">',
'<td class="x-treegrid-col">',
'<span class="x-tree-node-indent">', this.indentMarkup, "</span>",
'<img src="', this.emptyIcon, '" class="x-tree-ec-icon x-tree-elbow">',
'<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon', (a.icon ? " x-tree-node-inline-icon" : ""), (a.iconCls ? " "+a.iconCls : ""), '" unselectable="on">',
'<a hidefocus="on" class="x-tree-node-anchor" href="', a.href ? a.href : '#', '" tabIndex="1" ',
a.hrefTarget ? ' target="'+a.hrefTarget+'"' : '', '>',
'<span unselectable="on">', (c.tpl ? c.tpl.apply(a) : a[c.dataIndex] || c.text), '</span></a>',
'</td>'
];
for(i = 1, len = cols.length; i < len; i++){
c = cols[i];
buf.push(
'<td class="x-treegrid-col ', (c.cls ? c.cls : ''), '">',
'<div unselectable="on" class="x-treegrid-text"', (c.align ? ' style="text-align: ' + c.align + ';"' : ''), '>',
(c.tpl ? c.tpl.apply(a) : a[c.dataIndex]),
'</div>',
'</td>'
);
}
buf.push(
'</tr><tr class="x-tree-node-ct"><td colspan="', cols.length, '">',
'<table class="x-treegrid-node-ct-table" cellpadding="0" cellspacing="0" style="table-layout: fixed; display: none; width: ', t.innerCt.getWidth() ,'px;"><colgroup>'
);
for(i = 0, len = cols.length; i<len; i++) {
buf.push('<col style="width: ', (cols[i].hidden ? 0 : cols[i].width) ,'px;" />');
}
buf.push('</colgroup></table></td></tr></tbody>');
if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
this.wrap = Ext.DomHelper.insertHtml("beforeBegin", n.nextSibling.ui.getEl(), buf.join(''));
}else{
this.wrap = Ext.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(''));
}
this.elNode = this.wrap.childNodes[0];
this.ctNode = this.wrap.childNodes[1].firstChild.firstChild;
var cs = this.elNode.firstChild.childNodes;
this.indentNode = cs[0];
this.ecNode = cs[1];
this.iconNode = cs[2];
this.anchor = cs[3];
this.textNode = cs[3].firstChild;
},
// private
animExpand : function(cb){
this.ctNode.style.display = "";
Ext.ux.tree.TreeGridNodeUI.superclass.animExpand.call(this, cb);
}
});
Ext.ux.tree.TreeGridRootNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
isTreeGridNodeUI: true,
// private
render : function(){
if(!this.rendered){
this.wrap = this.ctNode = this.node.ownerTree.innerCt.dom;
this.node.expanded = true;
}
if(Ext.isWebKit) {
// weird table-layout: fixed issue in webkit
var ct = this.ctNode;
ct.style.tableLayout = null;
(function() {
ct.style.tableLayout = 'fixed';
}).defer(1);
}
},
destroy : function(){
if(this.elNode){
Ext.dd.Registry.unregister(this.elNode.id);
}
delete this.node;
},
collapse : Ext.emptyFn,
expand : Ext.emptyFn
});

View File

@ -1,10 +0,0 @@
Ext.tree.RenderColumn = Ext.extend(Ext.tree.Column, {
constructor: function(c) {
c.tpl = c.tpl || new Ext.XTemplate('{' + c.dataIndex + ':this.format}');
c.tpl.format = c.renderer;
c.tpl.col = this;
Ext.tree.RenderColumn.superclass.constructor.call(this, c);
}
});
Ext.reg('tgrendercolumn', Ext.tree.RenderColumn);

View File

@ -1,116 +0,0 @@
/*!
* Ext JS Library 3.1.0
* Copyright(c) 2006-2009 Ext JS, LLC
* licensing@extjs.com
* http://www.extjs.com/license
*/
Ext.ns('Ext.ux.tree');
/**
* @class Ext.ux.tree.TreeGridSorter
* @extends Ext.tree.TreeSorter
*/
Ext.ux.tree.TreeGridSorter = Ext.extend(Ext.tree.TreeSorter, {
/**
* @cfg {Array} sortClasses The CSS classes applied to a header when it is sorted. (defaults to <tt>['sort-asc', 'sort-desc']</tt>)
*/
sortClasses : ['sort-asc', 'sort-desc'],
/**
* @cfg {String} sortAscText The text displayed in the 'Sort Ascending' menu item (defaults to <tt>'Sort Ascending'</tt>)
*/
sortAscText : 'Sort Ascending',
/**
* @cfg {String} sortDescText The text displayed in the 'Sort Descending' menu item (defaults to <tt>'Sort Descending'</tt>)
*/
sortDescText : 'Sort Descending',
constructor : function(tree, config) {
if(!Ext.isObject(config)) {
config = {
property: tree.columns[0].dataIndex || 'text',
folderSort: true
}
}
Ext.ux.tree.TreeGridSorter.superclass.constructor.apply(this, arguments);
this.tree = tree;
tree.on('headerclick', this.onHeaderClick, this);
tree.ddAppendOnly = true;
me = this;
this.defaultSortFn = function(n1, n2){
var dsc = me.dir && me.dir.toLowerCase() == 'desc';
var p = me.property || 'text';
var sortType = me.sortType;
var fs = me.folderSort;
var cs = me.caseSensitive === true;
var leafAttr = me.leafAttr || 'leaf';
if(fs){
if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
return 1;
}
if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
return -1;
}
}
var v1 = sortType ? sortType(n1.attributes[p]) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
var v2 = sortType ? sortType(n2.attributes[p]) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
if(v1 < v2){
return dsc ? +1 : -1;
}else if(v1 > v2){
return dsc ? -1 : +1;
}else{
return 0;
}
};
tree.on('afterrender', this.onAfterTreeRender, this, {single: true});
tree.on('headermenuclick', this.onHeaderMenuClick, this);
},
onAfterTreeRender : function() {
var hmenu = this.tree.hmenu;
hmenu.insert(0,
{itemId:'asc', text: this.sortAscText, cls: 'xg-hmenu-sort-asc'},
{itemId:'desc', text: this.sortDescText, cls: 'xg-hmenu-sort-desc'}
);
this.updateSortIcon(0, 'asc');
},
onHeaderMenuClick : function(c, id, index) {
if(id === 'asc' || id === 'desc') {
this.onHeaderClick(c, null, index);
return false;
}
},
onHeaderClick : function(c, el, i) {
if(c && !this.tree.headersDisabled){
var me = this;
me.property = c.dataIndex;
me.dir = c.dir = (c.dir === 'desc' ? 'asc' : 'desc');
me.sortType = c.sortType;
me.caseSensitive === Ext.isBoolean(c.caseSensitive) ? c.caseSensitive : this.caseSensitive;
me.sortFn = c.sortFn || this.defaultSortFn;
this.tree.root.cascade(function(n) {
if(!n.isLeaf()) {
me.updateSort(me.tree, n);
}
});
this.updateSortIcon(i, c.dir);
}
},
// private
updateSortIcon : function(col, dir){
var sc = this.sortClasses;
var hds = this.tree.innerHd.select('td').removeClass(sc);
hds.item(col).addClass(sc[dir == 'desc' ? 1 : 0]);
}
});

15
deluge/ui/web/js/ext.js Normal file

File diff suppressed because one or more lines are too long

View File

@ -56,7 +56,7 @@ from deluge.ui.client import client, Client
from deluge.ui.coreconfig import CoreConfig from deluge.ui.coreconfig import CoreConfig
from deluge.ui.sessionproxy import SessionProxy from deluge.ui.sessionproxy import SessionProxy
from deluge.ui.web.common import _, compress from deluge.ui.web.common import Resource, _, compress
json = common.json json = common.json
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -102,14 +102,14 @@ class JSONException(Exception):
self.inner_exception = inner_exception self.inner_exception = inner_exception
Exception.__init__(self, str(inner_exception)) Exception.__init__(self, str(inner_exception))
class JSON(resource.Resource, component.Component): class JSON(Resource, component.Component):
""" """
A Twisted Web resource that exposes a JSON-RPC interface for web clients \ A Twisted Web resource that exposes a JSON-RPC interface for web clients \
to use. to use.
""" """
def __init__(self): def __init__(self):
resource.Resource.__init__(self) Resource.__init__(self)
component.Component.__init__(self, "JSON") component.Component.__init__(self, "JSON")
self._remote_methods = [] self._remote_methods = []
self._local_methods = {} self._local_methods = {}
@ -280,6 +280,7 @@ class JSON(resource.Resource, component.Component):
""" """
Handles all the POST requests made to the /json controller. Handles all the POST requests made to the /json controller.
""" """
Resource.render(self, request)
if request.method != "POST": if request.method != "POST":
request.setResponseCode(http.NOT_ALLOWED) request.setResponseCode(http.NOT_ALLOWED)
@ -567,7 +568,7 @@ class WebApi(JSONComponent):
dl.addCallback(on_complete) dl.addCallback(on_complete)
return d return d
def _on_got_files(self, torrent, d): def _on_got_files(self, torrent):
files = torrent.get("files") files = torrent.get("files")
file_progress = torrent.get("file_progress") file_progress = torrent.get("file_progress")
file_priorities = torrent.get("file_priorities") file_priorities = torrent.get("file_priorities")
@ -610,11 +611,11 @@ class WebApi(JSONComponent):
file_tree = uicommon.FileTree2(paths) file_tree = uicommon.FileTree2(paths)
file_tree.walk(walk) file_tree.walk(walk)
d.callback(file_tree.get_tree()) return file_tree.get_tree()
@export @export
def get_torrent_status(self, torrent_id, keys): def get_torrent_status(self, torrent_id, keys):
return component.get("SessionProxy").get_torrent_status(torrent_id, keys) return component.get("SessionProxy").get_torrent_status(torrent_id, map(str, keys))
@export @export
def get_torrent_files(self, torrent_id): def get_torrent_files(self, torrent_id):
@ -626,10 +627,8 @@ class WebApi(JSONComponent):
:returns: The torrents files in a tree :returns: The torrents files in a tree
:rtype: dictionary :rtype: dictionary
""" """
main_deferred = Deferred() return component.get("SessionProxy").get_torrent_status(torrent_id, FILES_KEYS
d = component.get("SessionProxy").get_torrent_status(torrent_id, FILES_KEYS) ).addCallback(self._on_got_files)
d.addCallback(self._on_got_files, main_deferred)
return main_deferred
@export @export
def download_torrent_from_url(self, url, cookie=None): def download_torrent_from_url(self, url, cookie=None):
@ -729,8 +728,7 @@ class WebApi(JSONComponent):
""" """
Return the hosts in the hostlist. Return the hosts in the hostlist.
""" """
log.debug("get_hosts called") return [dict(zip(('id', 'host', 'port', 'status'), tuple(host[HOSTS_ID:HOSTS_PORT+1]) + (_("Offline"),))) for host in self.host_list["hosts"]]
return [(tuple(host[HOSTS_ID:HOSTS_PORT+1]) + (_("Offline"),)) for host in self.host_list["hosts"]]
@export @export
def get_host_status(self, host_id): def get_host_status(self, host_id):
@ -742,12 +740,18 @@ class WebApi(JSONComponent):
""" """
def response(status, info=None): def response(status, info=None):
return host_id, host, port, status, info return dict (
id = host_id,
host = host,
port = port,
status = status,
version = info
)
try: try:
host_id, host, port, user, password = self.get_host(host_id) host_id, host, port, user, password = self.get_host(host_id)
except TypeError, e: except TypeError, e:
return response(_("Offline")) return None
def on_connect(connected, c, host_id): def on_connect(connected, c, host_id):
def on_info(info, c): def on_info(info, c):

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More