refactor forms
This commit is contained in:
parent
d32ffa7ace
commit
9df4492083
|
@ -31,7 +31,7 @@
|
|||
# this exception statement from your version. If you delete this exception
|
||||
# statement from all source files in the program, then also delete it here.
|
||||
|
||||
import lib.newforms as forms
|
||||
import lib.newforms_plus as forms
|
||||
import page_decorators as deco
|
||||
import lib.webpy022 as web
|
||||
from webserver_common import ws
|
||||
|
@ -43,37 +43,7 @@ import os
|
|||
groups = []
|
||||
blocks = forms.utils.datastructures.SortedDict()
|
||||
|
||||
class Form(forms.Form):
|
||||
info = ""
|
||||
title = "No Title"
|
||||
def __init__(self,data = None):
|
||||
if data == None:
|
||||
data = self.initial_data()
|
||||
forms.Form.__init__(self,data)
|
||||
|
||||
def initial_data(self):
|
||||
"override in subclass"
|
||||
return None
|
||||
|
||||
def start_save(self):
|
||||
"called by config_page"
|
||||
data = web.Storage(self.clean_data)
|
||||
self.validate(data)
|
||||
self.save(data)
|
||||
self.post_save()
|
||||
|
||||
def save(self, vars):
|
||||
"override in subclass"
|
||||
raise NotImplementedError()
|
||||
|
||||
def post_save(self):
|
||||
pass
|
||||
|
||||
def validate(self, data):
|
||||
pass
|
||||
|
||||
|
||||
class WebCfgForm(Form):
|
||||
class WebCfgForm(forms.Form):
|
||||
"config base for webui"
|
||||
def initial_data(self):
|
||||
return ws.config
|
||||
|
@ -82,7 +52,7 @@ class WebCfgForm(Form):
|
|||
ws.config.update(data)
|
||||
ws.save_config()
|
||||
|
||||
class CookieCfgForm(Form):
|
||||
class CookieCfgForm(forms.Form):
|
||||
"config base for webui"
|
||||
def initial_data(self):
|
||||
return ws.config
|
||||
|
@ -92,85 +62,13 @@ class CookieCfgForm(Form):
|
|||
ws.save_config()
|
||||
|
||||
|
||||
class CfgForm(Form):
|
||||
class CfgForm(forms.Form):
|
||||
"config base for deluge-cfg"
|
||||
def initial_data(self):
|
||||
return ws.proxy.get_config()
|
||||
def save(self, data):
|
||||
ws.proxy.set_config(dict(data))
|
||||
|
||||
|
||||
#convenience Input Fields.
|
||||
class _IntInput(forms.TextInput):
|
||||
"""
|
||||
because deluge-floats are edited as ints.
|
||||
"""
|
||||
def render(self, name, value, attrs=None):
|
||||
try:
|
||||
value = int(float(value))
|
||||
if value == -1:
|
||||
value = _("Unlimited")
|
||||
except:
|
||||
pass
|
||||
return forms.TextInput.render(self, name, value, attrs)
|
||||
|
||||
class CheckBox(forms.BooleanField):
|
||||
"Non Required ChoiceField"
|
||||
def __init__(self,label, **kwargs):
|
||||
forms.BooleanField.__init__(self,label=label,required=False,**kwargs)
|
||||
|
||||
class IntCombo(forms.ChoiceField):
|
||||
"""
|
||||
choices are the display-values
|
||||
returns int for the chosen display-value.
|
||||
"""
|
||||
def __init__(self, label, choices, **kwargs):
|
||||
forms.ChoiceField.__init__(self, label=label,
|
||||
choices=enumerate(choices), **kwargs)
|
||||
|
||||
def clean(self, value):
|
||||
return int(forms.ChoiceField.clean(self, value))
|
||||
|
||||
class DelugeInt(forms.IntegerField):
|
||||
def __init__(self, label , **kwargs):
|
||||
forms.IntegerField.__init__(self, label=label, min_value=-1,
|
||||
max_value=sys.maxint, widget=_IntInput, **kwargs)
|
||||
|
||||
def clean(self, value):
|
||||
if str(value).lower() == _('Unlimited').lower():
|
||||
value = -1
|
||||
return int(forms.IntegerField.clean(self, value))
|
||||
|
||||
class DelugeFloat(DelugeInt):
|
||||
def clean(self, value):
|
||||
return int(DelugeInt.clean(self, value))
|
||||
|
||||
class MultipleChoice(forms.MultipleChoiceField):
|
||||
#temp/test
|
||||
def __init__(self, label, choices, **kwargs):
|
||||
forms.MultipleChoiceField.__init__(self, label=label, choices=choices,
|
||||
widget=forms.CheckboxSelectMultiple, required=False)
|
||||
|
||||
class ServerFolder(forms.CharField):
|
||||
def __init__(self, label, **kwargs):
|
||||
forms.CharField.__init__(self, label=label,**kwargs)
|
||||
|
||||
def clean(self, value):
|
||||
value = value.rstrip('/').rstrip('\\')
|
||||
self.validate(value)
|
||||
return forms.CharField.clean(self, value)
|
||||
|
||||
def validate(self, value):
|
||||
if (value and not os.path.isdir(value)):
|
||||
raise forms.ValidationError(_("This folder does not exist."))
|
||||
|
||||
class Password(forms.CharField):
|
||||
def __init__(self, label, **kwargs):
|
||||
forms.CharField.__init__(self, label=label, widget=forms.PasswordInput,
|
||||
**kwargs)
|
||||
|
||||
#/fields
|
||||
|
||||
class config_page:
|
||||
"""
|
||||
web.py config page
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
# this exception statement from your version. If you delete this exception
|
||||
# statement from all source files in the program, then also delete it here.
|
||||
|
||||
import lib.newforms as forms
|
||||
import lib.newforms_plus as forms
|
||||
import config
|
||||
import utils
|
||||
from webserver_common import ws
|
||||
|
@ -42,7 +42,7 @@ class NetworkPorts(config.CfgForm ):
|
|||
info = _("Restart daemon after changing these values.")
|
||||
_port_from = forms.IntegerField(_("From"))
|
||||
_port_to = forms.IntegerField(_("To"))
|
||||
random_port = config.CheckBox(_("Random"))
|
||||
random_port = forms.CheckBox(_("Random"))
|
||||
|
||||
def initial_data(self):
|
||||
data = config.CfgForm.initial_data(self)
|
||||
|
@ -63,24 +63,24 @@ config.register_block('network','ports', NetworkPorts)
|
|||
|
||||
class NetworkExtra(config.CfgForm ):
|
||||
title = _("Extra's")
|
||||
dht = config.CheckBox(_("Mainline DHT"))
|
||||
upnp = config.CheckBox(_("UpNP"))
|
||||
natpmp = config.CheckBox(_("NAT-PMP"))
|
||||
utpex = config.CheckBox(_("Peer-Exchange"))
|
||||
lsd = config.CheckBox(_("LSD"))
|
||||
dht = forms.CheckBox(_("Mainline DHT"))
|
||||
upnp = forms.CheckBox(_("UpNP"))
|
||||
natpmp = forms.CheckBox(_("NAT-PMP"))
|
||||
utpex = forms.CheckBox(_("Peer-Exchange"))
|
||||
lsd = forms.CheckBox(_("LSD"))
|
||||
|
||||
config.register_block('network','extra', NetworkExtra)
|
||||
|
||||
class NetworkEnc(config.CfgForm ):
|
||||
title = _("Encryption")
|
||||
|
||||
_enc_choices = [_("Forced"),_("Enabled"),_("Disabled")]
|
||||
_level_choices = [_("Handshake"), _("Full") , _("Either")]
|
||||
_enc_choices = list(enumerate([_("Forced"),_("Enabled"),_("Disabled")]))
|
||||
_level_choices = list(enumerate([_("Handshake"), _("Full") , _("Either")]))
|
||||
|
||||
enc_in_policy = config.IntCombo(_("Inbound"), _enc_choices)
|
||||
enc_out_policy = config.IntCombo(_("Outbound"), _enc_choices)
|
||||
enc_level = config.IntCombo(_("Level"), _level_choices)
|
||||
enc_prefer_rc4 = config.CheckBox("Prefer to encrypt entire stream")
|
||||
enc_in_policy = forms.IntChoiceField(_("Inbound"), _enc_choices)
|
||||
enc_out_policy = forms.IntChoiceField(_("Outbound"), _enc_choices)
|
||||
enc_level = forms.IntChoiceField(_("Level"), _level_choices)
|
||||
enc_prefer_rc4 = forms.CheckBox("Prefer to encrypt entire stream")
|
||||
|
||||
config.register_block('network','encryption', NetworkEnc)
|
||||
|
||||
|
@ -88,44 +88,45 @@ config.register_block('network','encryption', NetworkEnc)
|
|||
class BandwithGlobal(config.CfgForm):
|
||||
title = _("Global")
|
||||
info = _("-1 = Unlimited")
|
||||
max_connections_global = config.DelugeInt(_("Maximum Connections"))
|
||||
max_download_speed = config.DelugeFloat(_("Maximum Download Speed (Kib/s)"))
|
||||
max_upload_speed = config.DelugeFloat(_("Maximum Upload Speed (Kib/s)"))
|
||||
max_upload_slots_global = config.DelugeInt(_("Maximum Upload Slots"))
|
||||
max_connections_global = forms.DelugeInt(_("Maximum Connections"))
|
||||
max_download_speed = forms.DelugeFloat(_("Maximum Download Speed (Kib/s)"))
|
||||
max_upload_speed = forms.DelugeFloat(_("Maximum Upload Speed (Kib/s)"))
|
||||
max_upload_slots_global = forms.DelugeInt(_("Maximum Upload Slots"))
|
||||
|
||||
config.register_block('bandwidth','global', BandwithGlobal)
|
||||
|
||||
class BandwithTorrent(config.CfgForm):
|
||||
title = _("Per Torrent")
|
||||
info = _("-1 = Unlimited")
|
||||
max_connections_per_torrent = config.DelugeInt(_("Maximum Connections"))
|
||||
max_upload_slots_per_torrent = config.DelugeInt(_("Maximum Upload Slots"))
|
||||
max_connections_per_torrent = forms.DelugeInt(_("Maximum Connections"))
|
||||
max_upload_slots_per_torrent = forms.DelugeInt(_("Maximum Upload Slots"))
|
||||
|
||||
config.register_block('bandwidth','torrent', BandwithTorrent)
|
||||
|
||||
|
||||
class Download(config.CfgForm):
|
||||
title = _("Download")
|
||||
download_location = config.ServerFolder(_("Store all downoads in"))
|
||||
torrentfiles_location = config.ServerFolder(_("Save .torrent files to"))
|
||||
autoadd_location = config.ServerFolder(_("Auto Add folder"), required=False)
|
||||
compact_allocation = config.CheckBox(_('Use Compact Allocation'))
|
||||
prioritize_first_last_pieces = config.CheckBox(
|
||||
download_location = forms.ServerFolder(_("Store all downoads in"))
|
||||
torrentfiles_location = forms.ServerFolder(_("Save .torrent files to"))
|
||||
autoadd_location = forms.ServerFolder(_("Auto Add folder"), required=False)
|
||||
compact_allocation = forms.CheckBox(_('Use Compact Allocation'))
|
||||
prioritize_first_last_pieces = forms.CheckBox(
|
||||
_('Prioritize first and last pieces'))
|
||||
|
||||
config.register_block('deluge','download', Download)
|
||||
|
||||
class Daemon(config.CfgForm):
|
||||
title = _("Daemon")
|
||||
info = _("Restart daemon and webui after changing these settings")
|
||||
daemon_port = forms.IntegerField(_("Port"))
|
||||
allow_remote = config.CheckBox(_("Allow Remote Connections"))
|
||||
allow_remote = forms.CheckBox(_("Allow Remote Connections"))
|
||||
|
||||
config.register_block('deluge','daemon', Daemon)
|
||||
|
||||
class Plugins(config.Form):
|
||||
class Plugins(forms.Form):
|
||||
title = _("Enabled Plugins")
|
||||
_choices = [(p,p) for p in ws.proxy.get_available_plugins()]
|
||||
enabled_plugins = config.MultipleChoice(_(""), _choices)
|
||||
enabled_plugins = forms.MultipleChoice(_(""), _choices)
|
||||
|
||||
def initial_data(self):
|
||||
return {'enabled_plugins':ws.proxy.get_enabled_plugins()}
|
||||
|
@ -136,19 +137,19 @@ class Plugins(config.Form):
|
|||
config.register_block('deluge','plugins', Plugins)
|
||||
|
||||
|
||||
class Queue(config.Form):
|
||||
class Queue(forms.Form):
|
||||
title = _("Queue")
|
||||
info = _("queue-cfg not finished")
|
||||
|
||||
queue_top = config.CheckBox(_("Queue new torrents to top"))
|
||||
total_active = config.DelugeInt(_("Total active torrents"))
|
||||
total_seeding = config.DelugeInt(_("Total active seeding"))
|
||||
total_downloading = config.DelugeInt(_("Total active downloading"))
|
||||
queue_top = forms.CheckBox(_("Queue new torrents to top"))
|
||||
total_active = forms.DelugeInt(_("Total active torrents"))
|
||||
total_seeding = forms.DelugeInt(_("Total active seeding"))
|
||||
total_downloading = forms.DelugeInt(_("Total active downloading"))
|
||||
|
||||
queue_bottom = config.CheckBox(_("Queue completed torrents to bottom"))
|
||||
stop_on_ratio = config.CheckBox(_("Stop seeding when ratio reaches"))
|
||||
stop_ratio = config.DelugeInt(_("TODO:float-edit-box"))
|
||||
remove_after_stop = config.CheckBox(_("Remve torrent when ratio reached"))
|
||||
queue_bottom = forms.CheckBox(_("Queue completed torrents to bottom"))
|
||||
stop_on_ratio = forms.CheckBox(_("Stop seeding when ratio reaches"))
|
||||
stop_ratio = forms.DelugeInt(_("TODO:float-edit-box"))
|
||||
remove_after_stop = forms.CheckBox(_("Remve torrent when ratio reached"))
|
||||
|
||||
def save(self, value):
|
||||
raise forms.ValidationError("SAVE:TODO")
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
# this exception statement from your version. If you delete this exception
|
||||
# statement from all source files in the program, then also delete it here.
|
||||
|
||||
import lib.newforms as forms
|
||||
import lib.newforms_plus as forms
|
||||
import config
|
||||
import utils
|
||||
from webserver_common import ws
|
||||
|
@ -41,11 +41,12 @@ class Template(config.WebCfgForm):
|
|||
title = _("Template")
|
||||
|
||||
_templates = [(t,t) for t in ws.get_templates()]
|
||||
_button_choices = [_('Text and image'), _('Image Only'), _('Text Only')]
|
||||
_button_choices = enumerate([_('Text and image'), _('Image Only')
|
||||
, _('Text Only')])
|
||||
|
||||
template = forms.ChoiceField( label=_("Template"), choices = _templates)
|
||||
button_style = config.IntCombo(_("Button style"),_button_choices)
|
||||
cache_templates = config.CheckBox(_("Cache templates"))
|
||||
button_style = forms.IntChoiceField(_("Button style"),_button_choices)
|
||||
cache_templates = forms.CheckBox(_("Cache templates"))
|
||||
|
||||
def post_save(self):
|
||||
from render import render
|
||||
|
@ -62,7 +63,7 @@ class Server(config.WebCfgForm):
|
|||
|
||||
port = forms.IntegerField(label = _("Port"),min_value=80)
|
||||
|
||||
use_https = config.CheckBox(_("Use https"))
|
||||
use_https = forms.CheckBox(_("Use https"))
|
||||
|
||||
|
||||
def post_save(self):
|
||||
|
@ -70,12 +71,12 @@ class Server(config.WebCfgForm):
|
|||
#raise forms.ValidationError(
|
||||
# _("Manually restart server to apply these changes."))
|
||||
|
||||
class Password(config.Form):
|
||||
class Password(forms.Form):
|
||||
title = _("Password")
|
||||
|
||||
old_pwd = config.Password(_("Current Password"))
|
||||
new1 = config.Password(_("New Password"))
|
||||
new2 = config.Password(_("New Password (Confirm)"))
|
||||
old_pwd = forms.Password(_("Current Password"))
|
||||
new1 = forms.Password(_("New Password"))
|
||||
new2 = forms.Password(_("New Password (Confirm)"))
|
||||
|
||||
def save(self,data):
|
||||
ws.update_pwd(data.new1)
|
||||
|
|
|
@ -9,7 +9,7 @@ from widgets import TextInput, Textarea, HiddenInput, MultipleHiddenInput
|
|||
from util import flatatt, StrAndUnicode, ErrorDict, ErrorList, ValidationError
|
||||
import copy
|
||||
|
||||
__all__ = ('BaseForm', 'Form')
|
||||
#__all__ = ('BaseForm', 'Form')
|
||||
|
||||
NON_FIELD_ERRORS = '__all__'
|
||||
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) Martijn Voncken 2008 <mvoncken@gmail.com>
|
||||
# Django Lisence, see ./newforms/LICENCE
|
||||
#
|
||||
|
||||
from newforms import *
|
||||
import newforms
|
||||
from newforms.forms import BoundField
|
||||
|
||||
import sys, os
|
||||
|
||||
|
||||
import webpy022 as web #todo:remove this dependency.
|
||||
|
||||
#Form
|
||||
class FilteredForm(newforms.Form):
|
||||
"""
|
||||
used to enable more complex layouts.
|
||||
the filter argument contains the names of the fields to render.
|
||||
"""
|
||||
def _html_output_filtered(self, normal_row, error_row, row_ender, help_text_html, errors_on_separate_row, filter):
|
||||
"""
|
||||
Helper function for outputting HTML. Used by as_table(), as_ul(), as_p().
|
||||
newforms_plus: 99% c&p from newforms, added filter.
|
||||
"""
|
||||
top_errors = self.non_field_errors() # Errors that should be displayed above all fields.
|
||||
output, hidden_fields = [], []
|
||||
for name, field in self.fields.items():
|
||||
#FilteredForm
|
||||
if (filter != None) and (not name in filter):
|
||||
continue
|
||||
#/FilteredForm
|
||||
bf = BoundField(self, field, name)
|
||||
bf_errors = ErrorList([escape(error) for error in bf.errors]) # Escape and cache in local variable.
|
||||
if bf.is_hidden:
|
||||
if bf_errors:
|
||||
top_errors.extend(['(Hidden field %s) %s' % (name, e) for e in bf_errors])
|
||||
hidden_fields.append(unicode(bf))
|
||||
else:
|
||||
if errors_on_separate_row and bf_errors:
|
||||
output.append(error_row % bf_errors)
|
||||
label = bf.label and bf.label_tag(escape(bf.label + ':')) or ''
|
||||
if field.help_text:
|
||||
help_text = help_text_html % field.help_text
|
||||
else:
|
||||
help_text = u''
|
||||
output.append(normal_row % {'errors': bf_errors, 'label': label, 'field': unicode(bf), 'help_text': help_text})
|
||||
if top_errors:
|
||||
output.insert(0, error_row % top_errors)
|
||||
if hidden_fields: # Insert any hidden fields in the last row.
|
||||
str_hidden = u''.join(hidden_fields)
|
||||
if output:
|
||||
last_row = output[-1]
|
||||
# Chop off the trailing row_ender (e.g. '</td></tr>') and insert the hidden fields.
|
||||
output[-1] = last_row[:-len(row_ender)] + str_hidden + row_ender
|
||||
else: # If there aren't any rows in the output, just append the hidden fields.
|
||||
output.append(str_hidden)
|
||||
return u'\n'.join(output)
|
||||
|
||||
def as_table(self , filter = None):
|
||||
"Returns this form rendered as HTML <tr>s -- excluding the <table></table>."
|
||||
return self._html_output_filtered(u'<tr><th>%(label)s</th><td>%(errors)s%(field)s%(help_text)s</td></tr>', u'<tr><td colspan="2">%s</td></tr>', '</td></tr>', u'<br />%s', False, filter)
|
||||
|
||||
def as_ul(self, filter = None):
|
||||
"Returns this form rendered as HTML <li>s -- excluding the <ul></ul>."
|
||||
return self._html_output_filtered(u'<li>%(errors)s%(label)s %(field)s%(help_text)s</li>', u'<li>%s</li>', '</li>', u' %s', False , filter)
|
||||
|
||||
def as_p(self , filter = None):
|
||||
"Returns this form rendered as HTML <p>s."
|
||||
return self._html_output_filtered(u'<p>%(label)s %(field)s%(help_text)s</p>', u'<p>%s</p>', '</p>', u' %s', True, filter)
|
||||
|
||||
class Form(newforms.Form):
|
||||
info = ""
|
||||
title = "No Title"
|
||||
def __init__(self,data = None):
|
||||
if data == None:
|
||||
data = self.initial_data()
|
||||
newforms.Form.__init__(self,data)
|
||||
|
||||
def initial_data(self):
|
||||
"override in subclass"
|
||||
return None
|
||||
|
||||
def start_save(self):
|
||||
"called by config_page"
|
||||
data = web.Storage(self.clean_data)
|
||||
self.validate(data)
|
||||
self.save(data)
|
||||
self.post_save()
|
||||
|
||||
def save(self, vars):
|
||||
"override in subclass"
|
||||
raise NotImplementedError()
|
||||
|
||||
def post_save(self):
|
||||
pass
|
||||
|
||||
def validate(self, data):
|
||||
pass
|
||||
|
||||
|
||||
#convenience Input Fields.
|
||||
class CheckBox(newforms.BooleanField):
|
||||
"Non Required BooleanField,why the f is it required by default?"
|
||||
def __init__(self,label, **kwargs):
|
||||
newforms.BooleanField.__init__(self,label=label,required=False,**kwargs)
|
||||
|
||||
class IntChoiceField(newforms.ChoiceField):
|
||||
"""same as ChoiceField, but returns an int
|
||||
hint : Use IntChoiceField(choices=enumerate("list","of","strings"]))
|
||||
for index-based values on a list of strings.
|
||||
"""
|
||||
def __init__(self, label, choices, **kwargs):
|
||||
newforms.ChoiceField.__init__(self, label=label, choices=choices,**kwargs)
|
||||
|
||||
def clean(self, value):
|
||||
return int(newforms.ChoiceField.clean(self, value))
|
||||
|
||||
class MultipleChoice(newforms.MultipleChoiceField):
|
||||
#temp/test/debug!!
|
||||
"Non Required MultipleChoiceField,why the f is it required by default?"
|
||||
def __init__(self, label, choices, **kwargs):
|
||||
newforms.MultipleChoiceField.__init__(self, label=label, choices=choices,
|
||||
widget=newforms.CheckboxSelectMultiple, required=False)
|
||||
|
||||
class ServerFolder(newforms.CharField):
|
||||
def __init__(self, label, **kwargs):
|
||||
newforms.CharField.__init__(self, label=label,**kwargs)
|
||||
|
||||
def clean(self, value):
|
||||
value = value.rstrip('/').rstrip('\\')
|
||||
self.validate(value)
|
||||
return newforms.CharField.clean(self, value)
|
||||
|
||||
def validate(self, value):
|
||||
if (value and not os.path.isdir(value)):
|
||||
raise newforms.ValidationError(_("This folder does not exist."))
|
||||
|
||||
class Password(newforms.CharField):
|
||||
def __init__(self, label, **kwargs):
|
||||
newforms.CharField.__init__(self, label=label, widget=newforms.PasswordInput,
|
||||
**kwargs)
|
||||
|
||||
#Deluge specific:
|
||||
class _DelugeIntInput(newforms.TextInput):
|
||||
"""
|
||||
because deluge-floats are edited as ints.
|
||||
"""
|
||||
def render(self, name, value, attrs=None):
|
||||
try:
|
||||
value = int(float(value))
|
||||
if value == -1:
|
||||
value = _("Unlimited")
|
||||
except:
|
||||
pass
|
||||
return newforms.TextInput.render(self, name, value, attrs)
|
||||
|
||||
class DelugeInt(newforms.IntegerField):
|
||||
def __init__(self, label , **kwargs):
|
||||
newforms.IntegerField.__init__(self, label=label, min_value=-1,
|
||||
max_value=sys.maxint, widget=_DelugeIntInput, **kwargs)
|
||||
|
||||
def clean(self, value):
|
||||
if str(value).lower() == _('Unlimited').lower():
|
||||
value = -1
|
||||
return int(newforms.IntegerField.clean(self, value))
|
||||
|
||||
class DelugeFloat(DelugeInt):
|
||||
def clean(self, value):
|
||||
return int(DelugeInt.clean(self, value))
|
||||
|
||||
#/fields
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ $for t in torrent_list:
|
|||
</div>
|
||||
|
||||
<div id="tableContainer" class="tableContainer">
|
||||
<table class="torrent_list" border=0 cellspacing=0 cellpadding=2 id="torrent_list">
|
||||
<table class="torrent_list" border=0 cellspacing=0 cellpadding=2 id="torrent_list" >
|
||||
<thead class="fixedHeader">
|
||||
<tr>
|
||||
$:(sort_head('calc_state_str', 'S'))
|
||||
|
|
Loading…
Reference in New Issue