index e7802dc78d496580d04df746444e3157164c6b0a..54bf622e8d0ae9316c43a20323f79ca81f25f76e 100644 (file)
extension, filename, generic)
filename = generic
- if self.templates.has_key(filename) and \
- stime < self.templates[filename].mtime:
+ if self.templates.has_key(src) and \
+ stime < self.templates[src].mtime:
# compiled template is up to date
- return self.templates[filename]
+ return self.templates[src]
# compile the template
- self.templates[filename] = pt = RoundupPageTemplate()
+ self.templates[src] = pt = RoundupPageTemplate()
pt.write(open(src).read())
pt.id = filename
pt.mtime = time.time()
filterspec = request.filterspec
sort = request.sort
group = request.group
+ else:
+ filterspec = {}
+ sort = (None,None)
+ group = (None,None)
if self.classname == 'user':
klass = HTMLUser
else:
if isinstance(prop, klass):
return htmlklass(self._client, self._nodeid, prop, item, value)
- raise KeyErorr, item
+ raise KeyError, item
def __getattr__(self, attr):
''' convenience access to properties '''
_('<th>Action</th>'),
_('<th>Args</th>'),
'</tr>']
+ current = {}
comments = {}
history = self._klass.history(self._nodeid)
history.sort()
+ timezone = self._db.getUserTimezone()
if direction == 'descending':
history.reverse()
+ for prop_n in self._props.keys():
+ prop = self[prop_n]
+ if isinstance(prop, HTMLProperty):
+ current[prop_n] = prop.plain()
+ # make link if hrefable
+ if (self._props.has_key(prop_n) and
+ isinstance(self._props[prop_n], hyperdb.Link)):
+ classname = self._props[prop_n].classname
+ if os.path.exists(os.path.join(self._db.config.TEMPLATES, classname + '.item')):
+ current[prop_n] = '<a href="%s%s">%s</a>'%(classname,
+ self._klass.get(self._nodeid, prop_n, None), current[prop_n])
+
for id, evt_date, user, action, args in history:
- date_s = str(evt_date).replace("."," ")
+ date_s = str(evt_date.local(timezone)).replace("."," ")
arg_s = ''
if action == 'link' and type(args) == type(()):
if len(args) == 3:
label = None
if label is not None:
if hrefable:
- cell.append('%s: <a href="%s%s">%s</a>\n'%(k,
- classname, args[k], label))
+ old = '<a href="%s%s">%s</a>'%(classname, args[k], label)
else:
- cell.append('%s: %s' % (k,label))
+ old = label;
+ cell.append('%s: %s' % (k,old))
+ if current.has_key(k):
+ cell[-1] += ' -> %s'%current[k]
+ current[k] = old
elif isinstance(prop, hyperdb.Date) and args[k]:
- d = date.Date(args[k])
+ d = date.Date(args[k]).local(timezone)
cell.append('%s: %s'%(k, str(d)))
+ if current.has_key(k):
+ if not current[k] == '(no value)' and current[k]:
+ current[k] = date.Date(current[k]).local(timezone)
+ cell[-1] += ' -> %s' % current[k]
+ current[k] = str(d)
elif isinstance(prop, hyperdb.Interval) and args[k]:
d = date.Interval(args[k])
cell.append('%s: %s'%(k, str(d)))
+ if current.has_key(k):
+ cell[-1] += ' -> %s'%current[k]
+ current[k] = str(d)
elif isinstance(prop, hyperdb.String) and args[k]:
cell.append('%s: %s'%(k, cgi.escape(args[k])))
+ if current.has_key(k):
+ cell[-1] += ' -> %s'%current[k]
+ current[k] = cgi.escape(args[k])
elif not args[k]:
- cell.append('%s: (no value)\n'%k)
+ if current.has_key(k):
+ cell.append('%s: %s'%(k, current[k]))
+ current[k] = '(no value)'
+ else:
+ cell.append('%s: (no value)'%k)
else:
- cell.append('%s: %s\n'%(k, str(args[k])))
+ cell.append('%s: %s'%(k, str(args[k])))
+ if current.has_key(k):
+ cell[-1] += ' -> %s'%current[k]
+ current[k] = str(args[k])
else:
# property no longer exists
comments['no_exist'] = _('''<em>The indicated property
# create a new request and override the specified args
req = HTMLRequest(self._client)
req.classname = self._klass.get(self._nodeid, 'klass')
- req.updateFromURL(self._klass.get(self._nodeid, 'url'))
+ name = self._klass.get(self._nodeid, 'name')
+ req.updateFromURL(self._klass.get(self._nodeid, 'url') +
+ '&:queryname=%s'%urllib.quote(name))
# new template, using the specified classname and request
pt = Templates(self._db.config.TEMPLATES).get(req.classname, 'search')
return cmp(self._value, other)
class StringHTMLProperty(HTMLProperty):
- def plain(self, escape=0):
+ hyper_re = re.compile(r'((?P<url>\w{3,6}://\S+)|'
+ r'(?P<email>[\w\.]+@[\w\.\-]+)|'
+ r'(?P<item>(?P<class>[a-z_]+)(?P<id>\d+)))')
+ def _hyper_repl(self, match):
+ if match.group('url'):
+ s = match.group('url')
+ return '<a href="%s">%s</a>'%(s, s)
+ elif match.group('email'):
+ s = match.group('email')
+ return '<a href="mailto:%s">%s</a>'%(s, s)
+ else:
+ s = match.group('item')
+ s1 = match.group('class')
+ s2 = match.group('id')
+ try:
+ # make sure s1 is a valid tracker classname
+ self._db.getclass(s1)
+ return '<a href="%s">%s %s</a>'%(s, s1, s2)
+ except KeyError:
+ return '%s%s'%(s1, s2)
+
+ def plain(self, escape=0, hyperlink=0):
''' Render a "plain" representation of the property
+
+ "escape" turns on/off HTML quoting
+ "hyperlink" turns on/off in-text hyperlinking of URLs, email
+ addresses and designators
'''
if self._value is None:
return ''
if escape:
- return cgi.escape(str(self._value))
- return str(self._value)
+ s = cgi.escape(str(self._value))
+ else:
+ s = str(self._value)
+ if hyperlink:
+ if not escape:
+ s = cgi.escape(s)
+ s = self.hyper_re.sub(self._hyper_repl, s)
+ return s
def stext(self, escape=0):
''' Render the value of the property as StructuredText.
def confirm(self, size = 30):
''' Render a second form edit field for the property, used for
confirmation that the user typed the password correctly. Generates
- a field with name "name:confirm".
+ a field with name ":confirm:name".
'''
- return '<input type="password" name="%s:confirm" size="%s">'%(
+ return '<input type="password" name=":confirm:%s" size="%s">'%(
self._name, size)
class NumberHTMLProperty(HTMLProperty):
def plain(self):
''' Render a "plain" representation of the property
'''
- if self.value is None:
+ if self._value is None:
return ''
return self._value and "Yes" or "No"
'''
if self._value is None:
return ''
- return str(self._value)
+ return str(self._value.local(self._db.getUserTimezone()))
+
+ def now(self):
+ ''' Return the current time.
+
+ This is useful for defaulting a new value. Returns a
+ DateHTMLProperty.
+ '''
+ return DateHTMLProperty(self._client, self._nodeid, self._prop,
+ self._name, date.Date('.'))
def field(self, size = 30):
''' Render a form edit field for the property
if self._value is None:
value = ''
else:
- value = cgi.escape(str(self._value))
+ value = cgi.escape(str(self._value.local(self._db.getUserTimezone())))
value = '"'.join(value.split('"'))
return '<input name="%s" value="%s" size="%s">'%(self._name, value, size)
'''
return self._value.pretty()
+ def local(self, offset):
+ ''' Return the date/time as a local (timezone offset) date/time.
+ '''
+ return DateHTMLProperty(self._client, self._nodeid, self._prop,
+ self._name, self._value.local(offset))
+
class IntervalHTMLProperty(HTMLProperty):
def plain(self):
''' Render a "plain" representation of the property
entry identified by the assignedto property on item, and then the
name property of that user)
'''
+ def __init__(self, *args):
+ HTMLProperty.__init__(self, *args)
+ # if we're representing a form value, then the -1 from the form really
+ # should be a None
+ if str(self._value) == '-1':
+ self._value = None
+
def __getattr__(self, attr):
''' return a new HTMLItem '''
#print 'Link.getattr', (self, attr, self._value)
else:
s = ''
l.append(_('<option %svalue="-1">- no selection -</option>')%s)
+
+ # make sure we list the current value if it's retired
+ if self._value and self._value not in options:
+ options.insert(0, self._value)
+
for optionid in options:
# get the option value, and if it's None use an empty string
option = linkcl.get(optionid, k) or ''
else:
sort_on = ('+', linkcl.labelprop())
options = linkcl.filter(None, conditions, sort_on, (None, None))
+
+ # make sure we list the current value if it's retired
+ if self._value and self._value not in options:
+ options.insert(0, self._value)
+
for optionid in options:
# get the option value, and if it's None use an empty string
option = linkcl.get(optionid, k) or ''
return klass(self._client, self._prop.classname, value)
def __contains__(self, value):
- ''' Support the "in" operator
+ ''' Support the "in" operator. We have to make sure the passed-in
+ value is a string first, not a *HTMLProperty.
'''
- return value in self._value
+ return str(value) in self._value
def reverse(self):
''' return the list in reverse order
height = height or min(len(options), 7)
l = ['<select multiple name="%s" size="%s">'%(self._name, height)]
k = linkcl.labelprop(1)
+
+ # make sure we list the current values if they're retired
+ for val in value:
+ if val not in options:
+ options.insert(0, val)
+
for optionid in options:
# get the option value, and if it's None use an empty string
option = linkcl.get(optionid, k) or ''
self.classname = client.classname
self.template = client.template
+ # the special char to use for special vars
+ self.special_char = '@'
+
self._post_init()
def _post_init(self):
'''
# extract the index display information from the form
self.columns = []
- if self.form.has_key(':columns'):
- self.columns = handleListCGIValue(self.form[':columns'])
+ for name in ':columns @columns'.split():
+ if self.form.has_key(name):
+ self.special_char = name[0]
+ self.columns = handleListCGIValue(self.form[name])
+ break
self.show = ShowDict(self.columns)
# sorting
self.sort = (None, None)
- if self.form.has_key(':sort'):
- sort = self.form[':sort'].value
- if sort.startswith('-'):
- self.sort = ('-', sort[1:])
- else:
- self.sort = ('+', sort)
- if self.form.has_key(':sortdir'):
- self.sort = ('-', self.sort[1])
+ for name in ':sort @sort'.split():
+ if self.form.has_key(name):
+ self.special_char = name[0]
+ sort = self.form[name].value
+ if sort.startswith('-'):
+ self.sort = ('-', sort[1:])
+ else:
+ self.sort = ('+', sort)
+ if self.form.has_key(self.special_char+'sortdir'):
+ self.sort = ('-', self.sort[1])
# grouping
self.group = (None, None)
- if self.form.has_key(':group'):
- group = self.form[':group'].value
- if group.startswith('-'):
- self.group = ('-', group[1:])
- else:
- self.group = ('+', group)
- if self.form.has_key(':groupdir'):
- self.group = ('-', self.group[1])
+ for name in ':group @group'.split():
+ if self.form.has_key(name):
+ self.special_char = name[0]
+ group = self.form[name].value
+ if group.startswith('-'):
+ self.group = ('-', group[1:])
+ else:
+ self.group = ('+', group)
+ if self.form.has_key(self.special_char+'groupdir'):
+ self.group = ('-', self.group[1])
# filtering
self.filter = []
- if self.form.has_key(':filter'):
- self.filter = handleListCGIValue(self.form[':filter'])
+ for name in ':filter @filter'.split():
+ if self.form.has_key(name):
+ self.special_char = name[0]
+ self.filter = handleListCGIValue(self.form[name])
+
self.filterspec = {}
db = self.client.db
if self.classname is not None:
# full-text search argument
self.search_text = None
- if self.form.has_key(':search_text'):
- self.search_text = self.form[':search_text'].value
+ for name in ':search_text @search_text'.split():
+ if self.form.has_key(name):
+ self.special_char = name[0]
+ self.search_text = self.form[name].value
# pagination - size and start index
# figure batch args
- if self.form.has_key(':pagesize'):
- self.pagesize = int(self.form[':pagesize'].value)
- else:
- self.pagesize = 50
- if self.form.has_key(':startwith'):
- self.startwith = int(self.form[':startwith'].value)
- else:
- self.startwith = 0
+ self.pagesize = 50
+ for name in ':pagesize @pagesize'.split():
+ if self.form.has_key(name):
+ self.special_char = name[0]
+ self.pagesize = int(self.form[name].value)
+
+ self.startwith = 0
+ for name in ':startwith @startwith'.split():
+ if self.form.has_key(name):
+ self.special_char = name[0]
+ self.startwith = int(self.form[name].value)
def updateFromURL(self, url):
''' Parse the URL for query args, and update my attributes using the
filterspec=1):
''' return the current index args as form elements '''
l = []
+ sc = self.special_char
s = '<input type="hidden" name="%s" value="%s">'
if columns and self.columns:
- l.append(s%(':columns', ','.join(self.columns)))
+ l.append(s%(sc+'columns', ','.join(self.columns)))
if sort and self.sort[1] is not None:
if self.sort[0] == '-':
val = '-'+self.sort[1]
else:
val = self.sort[1]
- l.append(s%(':sort', val))
+ l.append(s%(sc+'sort', val))
if group and self.group[1] is not None:
if self.group[0] == '-':
val = '-'+self.group[1]
else:
val = self.group[1]
- l.append(s%(':group', val))
+ l.append(s%(sc+'group', val))
if filter and self.filter:
- l.append(s%(':filter', ','.join(self.filter)))
+ l.append(s%(sc+'filter', ','.join(self.filter)))
if filterspec:
for k,v in self.filterspec.items():
- l.append(s%(k, ','.join(v)))
+ if type(v) == type([]):
+ l.append(s%(k, ','.join(v)))
+ else:
+ l.append(s%(k, v))
if self.search_text:
- l.append(s%(':search_text', self.search_text))
- l.append(s%(':pagesize', self.pagesize))
- l.append(s%(':startwith', self.startwith))
+ l.append(s%(sc+'search_text', self.search_text))
+ l.append(s%(sc+'pagesize', self.pagesize))
+ l.append(s%(sc+'startwith', self.startwith))
return '\n'.join(l)
def indexargs_url(self, url, args):
''' embed the current index args in a URL '''
+ sc = self.special_char
l = ['%s=%s'%(k,v) for k,v in args.items()]
if self.columns and not args.has_key(':columns'):
- l.append(':columns=%s'%(','.join(self.columns)))
+ l.append(sc+'columns=%s'%(','.join(self.columns)))
if self.sort[1] is not None and not args.has_key(':sort'):
if self.sort[0] == '-':
val = '-'+self.sort[1]
else:
val = self.sort[1]
- l.append(':sort=%s'%val)
+ l.append(sc+'sort=%s'%val)
if self.group[1] is not None and not args.has_key(':group'):
if self.group[0] == '-':
val = '-'+self.group[1]
else:
val = self.group[1]
- l.append(':group=%s'%val)
- if self.filter and not args.has_key(':columns'):
- l.append(':filter=%s'%(','.join(self.filter)))
+ l.append(sc+'group=%s'%val)
+ if self.filter and not args.has_key(':filter'):
+ l.append(sc+'filter=%s'%(','.join(self.filter)))
for k,v in self.filterspec.items():
if not args.has_key(k):
- l.append('%s=%s'%(k, ','.join(v)))
+ if type(v) == type([]):
+ l.append('%s=%s'%(k, ','.join(v)))
+ else:
+ l.append('%s=%s'%(k, v))
if self.search_text and not args.has_key(':search_text'):
- l.append(':search_text=%s'%self.search_text)
+ l.append(sc+'search_text=%s'%self.search_text)
if not args.has_key(':pagesize'):
- l.append(':pagesize=%s'%self.pagesize)
+ l.append(sc+'pagesize=%s'%self.pagesize)
if not args.has_key(':startwith'):
- l.append(':startwith=%s'%self.startwith)
+ l.append(sc+'startwith=%s'%self.startwith)
return '%s?%s'%(url, '&'.join(l))
indexargs_href = indexargs_url