summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: cb9962c)
raw | patch | inline | side by side (parent: cb9962c)
author | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Mon, 9 Sep 2002 05:28:48 +0000 (05:28 +0000) | ||
committer | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Mon, 9 Sep 2002 05:28:48 +0000 (05:28 +0000) |
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@1098 57a73879-2fb5-44c3-a270-3262357dd7e2
index ccfc6c733c6f2db0f4c03ed6dedb56fbd1a4f09b..2120a736e13e82ac676d5d75beb1cb05bc67b9c9 100644 (file)
"""
-__version__='$Revision: 1.3 $'[11:-2]
+__version__='$Revision: 1.4 $'[11:-2]
import re, sys
from TALES import Engine, CompilerError, _valid_name, NAME_RE, \
object = apply(object, name)
continue
- if name[0] == '_':
- # Never allowed in a URL.
- raise AttributeError, name
+# if name[0] == '_':
+# # Never allowed in a URL.
+# raise AttributeError, name
# Try an attribute.
o = get(object, name, M)
diff --git a/roundup/cgi/cgitb.py b/roundup/cgi/cgitb.py
index 19c1c2765941aa4abc19a001fc6d107f3869e3e3..dce420e699b427d6b75ac3cedbe7290150029425 100644 (file)
--- a/roundup/cgi/cgitb.py
+++ b/roundup/cgi/cgitb.py
#
# This module was written by Ka-Ping Yee, <ping@lfw.org>.
#
-# $Id: cgitb.py,v 1.3 2002-09-06 07:23:29 richard Exp $
+# $Id: cgitb.py,v 1.4 2002-09-09 05:28:48 richard Exp $
__doc__ = """
Extended CGI traceback handler by Ka-Ping Yee, <ping@lfw.org>.
"""
-import sys, os, types, string, keyword, linecache, tokenize, inspect, pydoc
+import sys, os, types, string, keyword, linecache, tokenize, inspect
+import pydoc, traceback
from roundup.i18n import _
niceDict(' ', context.global_vars),
niceDict(' ', context.local_vars)))
# context._scope_stack))
+
+ l.append('\n')
+ l.append(''.join(traceback.format_exception(etype, evalue,
+ sys.exc_traceback)))
return head + cgi.escape('\n'.join(l)) + '</pre><p> </p>'
def html(context=5):
#
# $Log: not supported by cvs2svn $
+# Revision 1.3 2002/09/06 07:23:29 richard
+# tweak
+#
# Revision 1.2 2002/09/06 07:21:31 richard
# much nicer error messages when there's a templating error
#
index 40dff5942d91fb4c5c1e9a4a5c518a6cfd87a3a8..9292c49f194433f66a3d12bd28ef7dfbe4d35205 100644 (file)
''' Return HTMLClasses for valid class fetches
'''
def __init__(self, client):
- self.client = client
+ self._client = client
+
+ # we want config to be exposed
self.config = client.db.config
+
def __getattr__(self, attr):
try:
- self.client.db.getclass(attr)
+ self._client.db.getclass(attr)
except KeyError:
raise AttributeError, attr
- return HTMLClass(self.client, attr)
+ return HTMLClass(self._client, attr)
def classes(self):
- l = self.client.db.classes.keys()
+ l = self._client.db.classes.keys()
l.sort()
- return [HTMLClass(self.client, cn) for cn in l]
+ return [HTMLClass(self._client, cn) for cn in l]
class HTMLClass:
''' Accesses through a class (either through *class* or *db.<classname>*)
'''
def __init__(self, client, classname):
- self.client = client
- self.db = client.db
+ self._client = client
+ self._db = client.db
+
+ # we want classname to be exposed
self.classname = classname
if classname is not None:
- self.klass = self.db.getclass(self.classname)
- self.props = self.klass.getprops()
+ self._klass = self._db.getclass(self.classname)
+ self._props = self._klass.getprops()
def __repr__(self):
return '<HTMLClass(0x%x) %s>'%(id(self), self.classname)
return None
if item == 'creator':
# but we will be created by this user...
- return HTMLUser(self.client, 'user', self.client.userid)
+ return HTMLUser(self._client, 'user', self._client.userid)
# get the property
- prop = self.props[item]
+ prop = self._props[item]
# look up the correct HTMLProperty class
for klass, htmlklass in propclasses:
else:
value = None
if isinstance(prop, klass):
- return htmlklass(self.client, '', prop, item, value)
+ return htmlklass(self._client, '', prop, item, value)
# no good
raise KeyError, item
''' Return HTMLProperty for all props
'''
l = []
- for name, prop in self.props.items():
+ for name, prop in self._props.items():
for klass, htmlklass in propclasses:
if isinstance(prop, hyperdb.Multilink):
value = []
else:
value = None
if isinstance(prop, klass):
- l.append(htmlklass(self.client, '', prop, name, value))
+ l.append(htmlklass(self._client, '', prop, name, value))
return l
def list(self):
klass = HTMLUser
else:
klass = HTMLItem
- l = [klass(self.client, self.classname, x) for x in self.klass.list()]
+ l = [klass(self._client, self.classname, x) for x in self._klass.list()]
return l
def csv(self):
p = csv.parser()
s = StringIO.StringIO()
s.write(p.join(props) + '\n')
- for nodeid in self.klass.list():
+ for nodeid in self._klass.list():
l = []
for name in props:
- value = self.klass.get(nodeid, name)
+ value = self._klass.get(nodeid, name)
if value is None:
l.append('')
elif isinstance(value, type([])):
l.append(':'.join(map(str, value)))
else:
- l.append(str(self.klass.get(nodeid, name)))
+ l.append(str(self._klass.get(nodeid, name)))
s.write(p.join(l) + '\n')
return s.getvalue()
def propnames(self):
''' Return the list of the names of the properties of this class.
'''
- idlessprops = self.klass.getprops(protected=0).keys()
+ idlessprops = self._klass.getprops(protected=0).keys()
idlessprops.sort()
return ['id'] + idlessprops
klass = HTMLUser
else:
klass = HTMLItem
- l = [klass(self.client, self.classname, x)
- for x in self.klass.filter(None, filterspec, sort, group)]
+ l = [klass(self._client, self.classname, x)
+ for x in self._klass.filter(None, filterspec, sort, group)]
return l
def classhelp(self, properties, label='?', width='400', height='400'):
''' Render this class with the given template.
'''
# create a new request and override the specified args
- req = HTMLRequest(self.client)
+ req = HTMLRequest(self._client)
req.classname = self.classname
req.update(kwargs)
# new template, using the specified classname and request
- pt = getTemplate(self.db.config.TEMPLATES, self.classname, name)
+ pt = getTemplate(self._db.config.TEMPLATES, self.classname, name)
# XXX handle PT rendering errors here nicely
try:
# use our fabricated request
- return pt.render(self.client, self.classname, req)
+ return pt.render(self._client, self.classname, req)
except PageTemplate.PTRuntimeError, message:
return '<strong>%s</strong><ol>%s</ol>'%(message,
cgi.escape('<li>'.join(pt._v_errors)))
''' Accesses through an *item*
'''
def __init__(self, client, classname, nodeid):
- self.client = client
- self.db = client.db
- self.classname = classname
- self.nodeid = nodeid
- self.klass = self.db.getclass(classname)
- self.props = self.klass.getprops()
+ self._client = client
+ self._db = client.db
+ self._classname = classname
+ self._nodeid = nodeid
+ self._klass = self._db.getclass(classname)
+ self._props = self._klass.getprops()
def __repr__(self):
- return '<HTMLItem(0x%x) %s %s>'%(id(self), self.classname, self.nodeid)
+ return '<HTMLItem(0x%x) %s %s>'%(id(self), self._classname,
+ self._nodeid)
def __getitem__(self, item):
''' return an HTMLProperty instance
'''
#print 'getitem', (self, item)
if item == 'id':
- return self.nodeid
+ return self._nodeid
# get the property
- prop = self.props[item]
+ prop = self._props[item]
# get the value, handling missing values
- value = self.klass.get(self.nodeid, item, None)
+ value = self._klass.get(self._nodeid, item, None)
if value is None:
- if isinstance(self.props[item], hyperdb.Multilink):
+ if isinstance(self._props[item], hyperdb.Multilink):
value = []
# look up the correct HTMLProperty class
for klass, htmlklass in propclasses:
if isinstance(prop, klass):
- return htmlklass(self.client, self.nodeid, prop, item, value)
+ return htmlklass(self._client, self._nodeid, prop, item, value)
raise KeyErorr, item
_('<th>Args</th>'),
'</tr>']
comments = {}
- history = self.klass.history(self.nodeid)
+ history = self._klass.history(self._nodeid)
history.sort()
if direction == 'descending':
history.reverse()
# try to get the relevant property and treat it
# specially
try:
- prop = self.props[k]
+ prop = self._props[k]
except KeyError:
prop = None
if prop is not None:
# figure what the link class is
classname = prop.classname
try:
- linkcl = self.db.getclass(classname)
+ linkcl = self._db.getclass(classname)
except KeyError:
labelprop = None
comments[classname] = _('''The linked class
%(classname)s no longer exists''')%locals()
labelprop = linkcl.labelprop(1)
hrefable = os.path.exists(
- os.path.join(self.db.config.TEMPLATES,
+ os.path.join(self._db.config.TEMPLATES,
classname+'.item'))
if isinstance(prop, hyperdb.Multilink) and \
'''
def __init__(self, client, classname, nodeid):
HTMLItem.__init__(self, client, 'user', nodeid)
- self.default_classname = client.classname
+ self._default_classname = client.classname
# used for security checks
- self.security = client.db.security
+ self._security = client.db.security
_marker = []
def hasPermission(self, role, classname=_marker):
''' Determine if the user has the Role.
be overidden for this test by suppling an alternate classname.
'''
if classname is self._marker:
- classname = self.default_classname
- return self.security.hasPermission(role, self.nodeid, classname)
+ classname = self._default_classname
+ return self._security.hasPermission(role, self._nodeid, classname)
class HTMLProperty:
''' String, Number, Date, Interval HTMLProperty
A wrapper object which may be stringified for the plain() behaviour.
'''
def __init__(self, client, nodeid, prop, name, value):
- self.client = client
- self.db = client.db
- self.nodeid = nodeid
- self.prop = prop
- self.name = name
- self.value = value
+ self._client = client
+ self._db = client.db
+ self._nodeid = nodeid
+ self._prop = prop
+ self._name = name
+ self._value = value
def __repr__(self):
- return '<HTMLProperty(0x%x) %s %r %r>'%(id(self), self.name, self.prop, self.value)
+ return '<HTMLProperty(0x%x) %s %r %r>'%(id(self), self._name, self._prop, self._value)
def __str__(self):
return self.plain()
def __cmp__(self, other):
if isinstance(other, HTMLProperty):
- return cmp(self.value, other.value)
- return cmp(self.value, other)
+ return cmp(self._value, other._value)
+ return cmp(self._value, other)
class StringHTMLProperty(HTMLProperty):
def plain(self, escape=0):
- if self.value is None:
+ if self._value is None:
return ''
if escape:
- return cgi.escape(str(self.value))
- return str(self.value)
+ return cgi.escape(str(self._value))
+ return str(self._value)
def stext(self, escape=0):
s = self.plain(escape=escape)
return StructuredText(s,level=1,header=0)
def field(self, size = 30):
- if self.value is None:
+ if self._value is None:
value = ''
else:
- value = cgi.escape(str(self.value))
+ value = cgi.escape(str(self._value))
value = '"'.join(value.split('"'))
- return '<input name="%s" value="%s" size="%s">'%(self.name, value, size)
+ return '<input name="%s" value="%s" size="%s">'%(self._name, value, size)
def multiline(self, escape=0, rows=5, cols=40):
- if self.value is None:
+ if self._value is None:
value = ''
else:
- value = cgi.escape(str(self.value))
+ value = cgi.escape(str(self._value))
value = '"'.join(value.split('"'))
return '<textarea name="%s" rows="%s" cols="%s">%s</textarea>'%(
- self.name, rows, cols, value)
+ self._name, rows, cols, value)
def email(self, escape=1):
''' fudge email '''
if self.value is None: value = ''
- else: value = str(self.value)
+ else: value = str(self._value)
value = value.replace('@', ' at ')
value = value.replace('.', ' ')
if escape:
class PasswordHTMLProperty(HTMLProperty):
def plain(self):
- if self.value is None:
+ if self._value is None:
return ''
return _('*encrypted*')
def field(self, size = 30):
- return '<input type="password" name="%s" size="%s">'%(self.name, size)
+ return '<input type="password" name="%s" size="%s">'%(self._name, size)
class NumberHTMLProperty(HTMLProperty):
def plain(self):
- return str(self.value)
+ return str(self._value)
def field(self, size = 30):
- if self.value is None:
+ if self._value is None:
value = ''
else:
- value = cgi.escape(str(self.value))
+ value = cgi.escape(str(self._value))
value = '"'.join(value.split('"'))
- return '<input name="%s" value="%s" size="%s">'%(self.name, value, size)
+ return '<input name="%s" value="%s" size="%s">'%(self._name, value, size)
class BooleanHTMLProperty(HTMLProperty):
def plain(self):
if self.value is None:
return ''
- return self.value and "Yes" or "No"
+ return self._value and "Yes" or "No"
def field(self):
- checked = self.value and "checked" or ""
- s = '<input type="radio" name="%s" value="yes" %s>Yes'%(self.name,
+ checked = self._value and "checked" or ""
+ s = '<input type="radio" name="%s" value="yes" %s>Yes'%(self._name,
checked)
if checked:
checked = ""
else:
checked = "checked"
- s += '<input type="radio" name="%s" value="no" %s>No'%(self.name,
+ s += '<input type="radio" name="%s" value="no" %s>No'%(self._name,
checked)
return s
class DateHTMLProperty(HTMLProperty):
def plain(self):
- if self.value is None:
+ if self._value is None:
return ''
- return str(self.value)
+ return str(self._value)
def field(self, size = 30):
- if self.value is None:
+ if self._value is None:
value = ''
else:
- value = cgi.escape(str(self.value))
+ value = cgi.escape(str(self._value))
value = '"'.join(value.split('"'))
- return '<input name="%s" value="%s" size="%s">'%(self.name, value, size)
+ return '<input name="%s" value="%s" size="%s">'%(self._name, value, size)
def reldate(self, pretty=1):
- if not self.value:
+ if not self._value:
return ''
# figure the interval
- interval = date.Date('.') - self.value
+ interval = date.Date('.') - self._value
if pretty:
return interval.pretty()
return str(interval)
class IntervalHTMLProperty(HTMLProperty):
def plain(self):
- if self.value is None:
+ if self._value is None:
return ''
- return str(self.value)
+ return str(self._value)
def pretty(self):
- return self.value.pretty()
+ return self._value.pretty()
def field(self, size = 30):
- if self.value is None:
+ if self._value is None:
value = ''
else:
- value = cgi.escape(str(self.value))
+ value = cgi.escape(str(self._value))
value = '"'.join(value.split('"'))
- return '<input name="%s" value="%s" size="%s">'%(self.name, value, size)
+ return '<input name="%s" value="%s" size="%s">'%(self._name, value, size)
class LinkHTMLProperty(HTMLProperty):
''' Link HTMLProperty
'''
def __getattr__(self, attr):
''' return a new HTMLItem '''
- #print 'getattr', (self, attr, self.value)
- if not self.value:
+ #print 'getattr', (self, attr, self._value)
+ if not self._value:
raise AttributeError, "Can't access missing value"
- if self.prop.classname == 'user':
+ if self._prop.classname == 'user':
klass = HTMLItem
else:
klass = HTMLUser
- i = klass(self.client, self.prop.classname, self.value)
+ i = klass(self._client, self._prop.classname, self._value)
return getattr(i, attr)
def plain(self, escape=0):
- if self.value is None:
+ if self._value is None:
return _('[unselected]')
- linkcl = self.db.classes[self.prop.classname]
+ linkcl = self._db.classes[self._prop.classname]
k = linkcl.labelprop(1)
- value = str(linkcl.get(self.value, k))
+ value = str(linkcl.get(self._value, k))
if escape:
value = cgi.escape(value)
return value
def field(self):
- linkcl = self.db.getclass(self.prop.classname)
+ linkcl = self._db.getclass(self._prop.classname)
if linkcl.getprops().has_key('order'):
sort_on = 'order'
else:
if optionid == value:
s = 'selected '
if showid:
- lab = '%s%s: %s'%(self.prop.classname, optionid, option)
+ lab = '%s%s: %s'%(self._prop.classname, optionid, option)
else:
lab = option
if size is not None and len(lab) > size:
return '\n'.join(l)
def download(self, showid=0):
- linkname = self.prop.classname
- linkcl = self.db.getclass(linkname)
+ linkname = self._prop.classname
+ linkcl = self._db.getclass(linkname)
k = linkcl.labelprop(1)
- linkvalue = cgi.escape(str(linkcl.get(self.value, k)))
+ linkvalue = cgi.escape(str(linkcl.get(self._value, k)))
if showid:
label = value
title = ' title="%s"'%linkvalue
else:
label = linkvalue
title = ''
- return '<a href="%s%s/%s"%s>%s</a>'%(linkname, self.value,
+ return '<a href="%s%s/%s"%s>%s</a>'%(linkname, self._value,
linkvalue, title, label)
def menu(self, size=None, height=None, showid=0, additional=[],
**conditions):
- value = self.value
+ value = self._value
# sort function
- sortfunc = make_sort_function(self.db, self.prop.classname)
+ sortfunc = make_sort_function(self._db, self._prop.classname)
# force the value to be a single choice
if isinstance(value, type('')):
value = value[0]
- linkcl = self.db.getclass(self.prop.classname)
- l = ['<select name="%s">'%self.name]
+ linkcl = self._db.getclass(self._prop.classname)
+ l = ['<select name="%s">'%self._name]
k = linkcl.labelprop(1)
s = ''
if value is None:
if value in [optionid, option]:
s = 'selected '
if showid:
- lab = '%s%s: %s'%(self.prop.classname, optionid, option)
+ lab = '%s%s: %s'%(self._prop.classname, optionid, option)
else:
lab = option
if size is not None and len(lab) > size:
'''
def __len__(self):
''' length of the multilink '''
- return len(self.value)
+ return len(self._value)
def __getattr__(self, attr):
''' no extended attribute accesses make sense here '''
''' iterate and return a new HTMLItem
'''
#print 'getitem', (self, num)
- value = self.value[num]
- if self.prop.classname == 'user':
+ value = self._value[num]
+ if self._prop.classname == 'user':
klass = HTMLUser
else:
klass = HTMLItem
- return klass(self.client, self.prop.classname, value)
+ return klass(self._client, self._prop.classname, value)
def reverse(self):
''' return the list in reverse order
'''
- l = self.value[:]
+ l = self._value[:]
l.reverse()
- if self.prop.classname == 'user':
+ if self._prop.classname == 'user':
klass = HTMLUser
else:
klass = HTMLItem
- return [klass(self.client, self.prop.classname, value) for value in l]
+ return [klass(self._client, self._prop.classname, value) for value in l]
def plain(self, escape=0):
- linkcl = self.db.classes[self.prop.classname]
+ linkcl = self._db.classes[self._prop.classname]
k = linkcl.labelprop(1)
labels = []
- for v in self.value:
+ for v in self._value:
labels.append(linkcl.get(v, k))
value = ', '.join(labels)
if escape:
return value
def field(self, size=30, showid=0):
- sortfunc = make_sort_function(self.db, self.prop.classname)
- linkcl = self.db.getclass(self.prop.classname)
- value = self.value[:]
+ sortfunc = make_sort_function(self._db, self._prop.classname)
+ linkcl = self._db.getclass(self._prop.classname)
+ value = self._value[:]
if value:
value.sort(sortfunc)
# map the id to the label property
k = linkcl.labelprop(1)
value = [linkcl.get(v, k) for v in value]
value = cgi.escape(','.join(value))
- return '<input name="%s" size="%s" value="%s">'%(self.name, size, value)
+ return '<input name="%s" size="%s" value="%s">'%(self._name, size, value)
def menu(self, size=None, height=None, showid=0, additional=[],
**conditions):
- value = self.value
+ value = self._value
# sort function
- sortfunc = make_sort_function(self.db, self.prop.classname)
+ sortfunc = make_sort_function(self._db, self._prop.classname)
- linkcl = self.db.getclass(self.prop.classname)
+ linkcl = self._db.getclass(self._prop.classname)
if linkcl.getprops().has_key('order'):
sort_on = ('+', 'order')
else:
sort_on = ('+', linkcl.labelprop())
options = linkcl.filter(None, conditions, sort_on, (None,None))
height = height or min(len(options), 7)
- l = ['<select multiple name="%s" size="%s">'%(self.name, height)]
+ l = ['<select multiple name="%s" size="%s">'%(self._name, height)]
k = linkcl.labelprop(1)
for optionid in options:
option = linkcl.get(optionid, k)
if optionid in value or option in value:
s = 'selected '
if showid:
- lab = '%s%s: %s'%(self.prop.classname, optionid, option)
+ lab = '%s%s: %s'%(self._prop.classname, optionid, option)
else:
lab = option
if size is not None and len(lab) > size:
diff --git a/roundup/templates/classic/html/issue.index b/roundup/templates/classic/html/issue.index
index a1f41f639eaa0cd66f0102cd387873ef17203fd7..177a68a275dcc564577e0730d148cf95aad0af6d 100644 (file)
<select name=":sort">
<option value="">- nothing -</option>
<option tal:repeat="col context/properties"
- tal:attributes="value col/name;
- selected python:col.name == request.sort[1]"
- tal:content="col/name">column</option>
+ tal:attributes="value col/_name;
+ selected python:col._name == request.sort[1]"
+ tal:content="col/_name">column</option>
</select>
</td>
<th>Descending:</th>
<select name=":group">
<option value="">- nothing -</option>
<option tal:repeat="col context/properties"
- tal:attributes="value col/name;
- selected python:col.name == request.group[1]"
- tal:content="col/name">column</option>
+ tal:attributes="value col/_name;
+ selected python:col._name == request.group[1]"
+ tal:content="col/_name">column</option>
</select>
</td>
<th>Descending:</th>
index 96f1a0c359b24ddc3a2ab196d1408f835e5c3c64..a16ef79c0696242b60aafa95ece1da3aec0c58ec 100644 (file)
<p class="classblock" tal:condition="request/user/queries">
<b>Your Queries</b><br>
<a tal:repeat="qs request/user/queries"
- tal:attributes="href python:'%s%s'%(qs['klass'], qs['url'])"
+ tal:attributes="href string:${qs/klass}${qs/url}"
tal:content="qs/name">link</a>
</p>
index 59ca1c6a0df46bceede6c317567abaa56098d075..681d75b6b50cb0d7cd1bdf91535a3654d451ee5c 100755 (executable)
-<table border=0 cellspacing=0 cellpadding=2>
-<tr class="strong-header">
- <td colspan=2>Query</td>
+<table class="form">
+<tr>
+ <th>Class</th>
+ <td tal:content="structure context/klass/field"></td>
</tr>
-<tr bgcolor="ffffea">
- <td width=1% nowrap class="form-label" align=right>Class</td>
- <td class="form-text"><display call="plain('klass')"></td>
+<tr>
+ <th>Name</th>
+ <td tal:content="structure context/name/field"></td>
</tr>
-<tr bgcolor="ffffea">
- <td width=1% nowrap class="form-label" align=right>Name</td>
- <td class="form-text"><display call="field('name')"></td>
+<tr>
+ <td colspan=2>
+ hrm. filterspec here...
+ <display call="filterspec('klass','url')">
+ </td>
</tr>
-<tr bgcolor="ffffea">
- <td colspan=2><display call="filterspec('klass','url')"></td>
-</tr>
-
-<tr bgcolor="ffffea">
- <td></td>
- <td class="form-text"><display call="submit()"></td>
+<tr>
+ <td> </td>
+ <td tal:content="structure context/submit">submit button here</td>
</tr>
</table>
index 96b3926e44e635baca81cebe53418bf6287fe5d1..724c6aa3f3dc3a079011db0401fda13041493654 100644 (file)
<tal:block tal:condition="context/id">
<table class="otherinfo" tal:condition="context/queries">
- <tr><th class="header">Queries</th></tr>
+ <tr><th colspan="2" class="header">Queries</th></tr>
+ <tr><th>Name</th><th>Display</th></tr>
<tr tal:repeat="query context/queries">
- <td tal:content="query">query</td>
+ <td><a tal:attributes="href string:query${query/id}"
+ tal:content="query/name"></a></td>
+ <td>
+ <a tal:attributes="href python:'%s%s'%(query['klass'], query['url'])">display</a>
+ </td>
</tr>
</table>