comparison roundup/template_funcs.py @ 934:fdcf16b444a9

Use a real parser for templates. Rewrite htmltemplate to use the parser (hack, hack). Move the "do_XXX" methods to template_funcs.py. Redo the funcion tests (but not Template tests - they're hopeless). Simplified query form in cgi_client. Ability to delete msgs, files, queries. Ability to edit the metadata on files.
author Gordon B. McMillan <gmcm@users.sourceforge.net>
date Tue, 13 Aug 2002 20:16:10 +0000
parents
children 57d09949380e
comparison
equal deleted inserted replaced
933:6bc4e245258f 934:fdcf16b444a9
1 import hyperdb, date, password
2 from i18n import _
3 import htmltemplate
4 import cgi, os, StringIO, urllib, types
5
6
7 def do_plain(client, classname, cl, props, nodeid, filterspec, property, escape=0, lookup=1):
8 ''' display a String property directly;
9
10 display a Date property in a specified time zone with an option to
11 omit the time from the date stamp;
12
13 for a Link or Multilink property, display the key strings of the
14 linked nodes (or the ids if the linked class has no key property)
15 when the lookup argument is true, otherwise just return the
16 linked ids
17 '''
18 if not nodeid and client.form is None:
19 return _('[Field: not called from item]')
20 propclass = props[property]
21 value = determine_value(cl, props, nodeid, filterspec, property)
22
23 if isinstance(propclass, hyperdb.Password):
24 value = _('*encrypted*')
25 elif isinstance(propclass, hyperdb.Boolean):
26 value = value and "Yes" or "No"
27 elif isinstance(propclass, hyperdb.Link):
28 if value:
29 if lookup:
30 linkcl = client.db.classes[propclass.classname]
31 k = linkcl.labelprop(1)
32 value = linkcl.get(value, k)
33 else:
34 value = _('[unselected]')
35 elif isinstance(propclass, hyperdb.Multilink):
36 if value:
37 if lookup:
38 linkcl = client.db.classes[propclass.classname]
39 k = linkcl.labelprop(1)
40 labels = []
41 for v in value:
42 labels.append(linkcl.get(v, k))
43 value = ', '.join(labels)
44 else:
45 value = ', '.join(value)
46 else:
47 value = ''
48 else:
49 value = str(value)
50
51 if escape:
52 value = cgi.escape(value)
53 return value
54
55 def do_stext(client, classname, cl, props, nodeid, filterspec, property, escape=0):
56 '''Render as structured text using the StructuredText module
57 (see above for details)
58 '''
59 s = do_plain(client, classname, cl, props, nodeid, filterspec, property, escape=escape)
60 if not StructuredText:
61 return s
62 return StructuredText(s,level=1,header=0)
63
64 def determine_value(cl, props, nodeid, filterspec, property):
65 '''determine the value of a property using the node, form or
66 filterspec
67 '''
68 if nodeid:
69 value = cl.get(nodeid, property, None)
70 if value is None:
71 if isinstance(props[property], hyperdb.Multilink):
72 return []
73 return ''
74 return value
75 elif filterspec is not None:
76 if isinstance(props[property], hyperdb.Multilink):
77 return filterspec.get(property, [])
78 else:
79 return filterspec.get(property, '')
80 # TODO: pull the value from the form
81 if isinstance(props[property], hyperdb.Multilink):
82 return []
83 else:
84 return ''
85
86 def make_sort_function(client, filterspec, classname):
87 '''Make a sort function for a given class
88 '''
89 linkcl = client.db.getclass(classname)
90 if linkcl.getprops().has_key('order'):
91 sort_on = 'order'
92 else:
93 sort_on = linkcl.labelprop()
94 def sortfunc(a, b, linkcl=linkcl, sort_on=sort_on):
95 return cmp(linkcl.get(a, sort_on), linkcl.get(b, sort_on))
96 return sortfunc
97
98 def do_field(client, classname, cl, props, nodeid, filterspec, property, size=None, showid=0):
99 ''' display a property like the plain displayer, but in a text field
100 to be edited
101
102 Note: if you would prefer an option list style display for
103 link or multilink editing, use menu().
104 '''
105 if not nodeid and client.form is None and filterspec is None:
106 return _('[Field: not called from item]')
107 if size is None:
108 size = 30
109
110 propclass = props[property]
111
112 # get the value
113 value = determine_value(cl, props, nodeid, filterspec, property)
114 # now display
115 if (isinstance(propclass, hyperdb.String) or
116 isinstance(propclass, hyperdb.Date) or
117 isinstance(propclass, hyperdb.Interval)):
118 if value is None:
119 value = ''
120 else:
121 value = cgi.escape(str(value))
122 value = '&quot;'.join(value.split('"'))
123 s = '<input name="%s" value="%s" size="%s">'%(property, value, size)
124 elif isinstance(propclass, hyperdb.Boolean):
125 checked = value and "checked" or ""
126 s = '<input type="radio" name="%s" value="yes" %s>Yes'%(property, checked)
127 if checked:
128 checked = ""
129 else:
130 checked = "checked"
131 s += '<input type="radio" name="%s" value="no" %s>No'%(property, checked)
132 elif isinstance(propclass, hyperdb.Number):
133 s = '<input name="%s" value="%s" size="%s">'%(property, value, size)
134 elif isinstance(propclass, hyperdb.Password):
135 s = '<input type="password" name="%s" size="%s">'%(property, size)
136 elif isinstance(propclass, hyperdb.Link):
137 linkcl = client.db.getclass(propclass.classname)
138 if linkcl.getprops().has_key('order'):
139 sort_on = 'order'
140 else:
141 sort_on = linkcl.labelprop()
142 options = linkcl.filter(None, {}, [sort_on], [])
143 # TODO: make this a field display, not a menu one!
144 l = ['<select name="%s">'%property]
145 k = linkcl.labelprop(1)
146 if value is None:
147 s = 'selected '
148 else:
149 s = ''
150 l.append(_('<option %svalue="-1">- no selection -</option>')%s)
151 for optionid in options:
152 option = linkcl.get(optionid, k)
153 s = ''
154 if optionid == value:
155 s = 'selected '
156 if showid:
157 lab = '%s%s: %s'%(propclass.classname, optionid, option)
158 else:
159 lab = option
160 if size is not None and len(lab) > size:
161 lab = lab[:size-3] + '...'
162 lab = cgi.escape(lab)
163 l.append('<option %svalue="%s">%s</option>'%(s, optionid, lab))
164 l.append('</select>')
165 s = '\n'.join(l)
166 elif isinstance(propclass, hyperdb.Multilink):
167 sortfunc = make_sort_function(client, filterspec, propclass.classname)
168 linkcl = client.db.getclass(propclass.classname)
169 if value:
170 value.sort(sortfunc)
171 # map the id to the label property
172 if not showid:
173 k = linkcl.labelprop(1)
174 value = [linkcl.get(v, k) for v in value]
175 value = cgi.escape(','.join(value))
176 s = '<input name="%s" size="%s" value="%s">'%(property, size, value)
177 else:
178 s = _('Plain: bad propclass "%(propclass)s"')%locals()
179 return s
180
181 def do_multiline(client, classname, cl, props, nodeid, filterspec, property, rows=5, cols=40):
182 ''' display a string property in a multiline text edit field
183 '''
184 if not nodeid and client.form is None and filterspec is None:
185 return _('[Multiline: not called from item]')
186
187 propclass = props[property]
188
189 # make sure this is a link property
190 if not isinstance(propclass, hyperdb.String):
191 return _('[Multiline: not a string]')
192
193 # get the value
194 value = determine_value(cl, props, nodeid, filterspec, property)
195 if value is None:
196 value = ''
197
198 # display
199 return '<textarea name="%s" rows="%s" cols="%s">%s</textarea>'%(
200 property, rows, cols, value)
201
202 def do_menu(client, classname, cl, props, nodeid, filterspec, property, size=None, height=None, showid=0,
203 additional=[], **conditions):
204 ''' For a Link/Multilink property, display a menu of the available
205 choices
206
207 If the additional properties are specified, they will be
208 included in the text of each option in (brackets, with, commas).
209 '''
210 if not nodeid and client.form is None and filterspec is None:
211 return _('[Field: not called from item]')
212
213 propclass = props[property]
214
215 # make sure this is a link property
216 if not (isinstance(propclass, hyperdb.Link) or
217 isinstance(propclass, hyperdb.Multilink)):
218 return _('[Menu: not a link]')
219
220 # sort function
221 sortfunc = make_sort_function(client, filterspec, propclass.classname)
222
223 # get the value
224 value = determine_value(cl, props, nodeid, filterspec, property)
225
226 # display
227 if isinstance(propclass, hyperdb.Multilink):
228 linkcl = client.db.getclass(propclass.classname)
229 if linkcl.getprops().has_key('order'):
230 sort_on = 'order'
231 else:
232 sort_on = linkcl.labelprop()
233 options = linkcl.filter(None, conditions, [sort_on], [])
234 height = height or min(len(options), 7)
235 l = ['<select multiple name="%s" size="%s">'%(property, height)]
236 k = linkcl.labelprop(1)
237 for optionid in options:
238 option = linkcl.get(optionid, k)
239 s = ''
240 if optionid in value or option in value:
241 s = 'selected '
242 if showid:
243 lab = '%s%s: %s'%(propclass.classname, optionid, option)
244 else:
245 lab = option
246 if size is not None and len(lab) > size:
247 lab = lab[:size-3] + '...'
248 if additional:
249 m = []
250 for propname in additional:
251 m.append(linkcl.get(optionid, propname))
252 lab = lab + ' (%s)'%', '.join(m)
253 lab = cgi.escape(lab)
254 l.append('<option %svalue="%s">%s</option>'%(s, optionid,
255 lab))
256 l.append('</select>')
257 return '\n'.join(l)
258 if isinstance(propclass, hyperdb.Link):
259 # force the value to be a single choice
260 if type(value) is types.ListType:
261 value = value[0]
262 linkcl = client.db.getclass(propclass.classname)
263 l = ['<select name="%s">'%property]
264 k = linkcl.labelprop(1)
265 s = ''
266 if value is None:
267 s = 'selected '
268 l.append(_('<option %svalue="-1">- no selection -</option>')%s)
269 if linkcl.getprops().has_key('order'):
270 sort_on = 'order'
271 else:
272 sort_on = linkcl.labelprop()
273 options = linkcl.filter(None, conditions, [sort_on], [])
274 for optionid in options:
275 option = linkcl.get(optionid, k)
276 s = ''
277 if value in [optionid, option]:
278 s = 'selected '
279 if showid:
280 lab = '%s%s: %s'%(propclass.classname, optionid, option)
281 else:
282 lab = option
283 if size is not None and len(lab) > size:
284 lab = lab[:size-3] + '...'
285 if additional:
286 m = []
287 for propname in additional:
288 m.append(linkcl.get(optionid, propname))
289 lab = lab + ' (%s)'%', '.join(map(str, m))
290 lab = cgi.escape(lab)
291 l.append('<option %svalue="%s">%s</option>'%(s, optionid, lab))
292 l.append('</select>')
293 return '\n'.join(l)
294 return _('[Menu: not a link]')
295
296 #XXX deviates from spec
297 def do_link(client, classname, cl, props, nodeid, filterspec, property=None, is_download=0, showid=0):
298 '''For a Link or Multilink property, display the names of the linked
299 nodes, hyperlinked to the item views on those nodes.
300 For other properties, link to this node with the property as the
301 text.
302
303 If is_download is true, append the property value to the generated
304 URL so that the link may be used as a download link and the
305 downloaded file name is correct.
306 '''
307 if not nodeid and client.form is None:
308 return _('[Link: not called from item]')
309
310 # get the value
311 value = determine_value(cl, props, nodeid, filterspec, property)
312 propclass = props[property]
313 if isinstance(propclass, hyperdb.Boolean):
314 value = value and "Yes" or "No"
315 elif isinstance(propclass, hyperdb.Link):
316 if value in ('', None, []):
317 return _('[no %(propname)s]')%{'propname':property.capitalize()}
318 linkname = propclass.classname
319 linkcl = client.db.getclass(linkname)
320 k = linkcl.labelprop(1)
321 linkvalue = cgi.escape(str(linkcl.get(value, k)))
322 if showid:
323 label = value
324 title = ' title="%s"'%linkvalue
325 # note ... this should be urllib.quote(linkcl.get(value, k))
326 else:
327 label = linkvalue
328 title = ''
329 if is_download:
330 return '<a href="%s%s/%s"%s>%s</a>'%(linkname, value,
331 linkvalue, title, label)
332 else:
333 return '<a href="%s%s"%s>%s</a>'%(linkname, value, title, label)
334 elif isinstance(propclass, hyperdb.Multilink):
335 if value in ('', None, []):
336 return _('[no %(propname)s]')%{'propname':property.capitalize()}
337 linkname = propclass.classname
338 linkcl = client.db.getclass(linkname)
339 k = linkcl.labelprop(1)
340 l = []
341 for value in value:
342 linkvalue = cgi.escape(str(linkcl.get(value, k)))
343 if showid:
344 label = value
345 title = ' title="%s"'%linkvalue
346 # note ... this should be urllib.quote(linkcl.get(value, k))
347 else:
348 label = linkvalue
349 title = ''
350 if is_download:
351 l.append('<a href="%s%s/%s"%s>%s</a>'%(linkname, value,
352 linkvalue, title, label))
353 else:
354 l.append('<a href="%s%s"%s>%s</a>'%(linkname, value,
355 title, label))
356 return ', '.join(l)
357 if is_download:
358 if value in ('', None, []):
359 return _('[no %(propname)s]')%{'propname':property.capitalize()}
360 return '<a href="%s%s/%s">%s</a>'%(classname, nodeid,
361 value, value)
362 else:
363 if value in ('', None, []):
364 value = _('[no %(propname)s]')%{'propname':property.capitalize()}
365 return '<a href="%s%s">%s</a>'%(classname, nodeid, value)
366
367 def do_count(client, classname, cl, props, nodeid, filterspec, property, **args):
368 ''' for a Multilink property, display a count of the number of links in
369 the list
370 '''
371 if not nodeid:
372 return _('[Count: not called from item]')
373
374 propclass = props[property]
375 if not isinstance(propclass, hyperdb.Multilink):
376 return _('[Count: not a Multilink]')
377
378 # figure the length then...
379 value = cl.get(nodeid, property)
380 return str(len(value))
381
382 # XXX pretty is definitely new ;)
383 def do_reldate(client, classname, cl, props, nodeid, filterspec, property, pretty=0):
384 ''' display a Date property in terms of an interval relative to the
385 current date (e.g. "+ 3w", "- 2d").
386
387 with the 'pretty' flag, make it pretty
388 '''
389 if not nodeid and client.form is None:
390 return _('[Reldate: not called from item]')
391
392 propclass = props[property]
393 if not isinstance(propclass, hyperdb.Date):
394 return _('[Reldate: not a Date]')
395
396 if nodeid:
397 value = cl.get(nodeid, property)
398 else:
399 return ''
400 if not value:
401 return ''
402
403 # figure the interval
404 interval = date.Date('.') - value
405 if pretty:
406 if not nodeid:
407 return _('now')
408 return interval.pretty()
409 return str(interval)
410
411 def do_download(client, classname, cl, props, nodeid, filterspec, property, **args):
412 ''' show a Link("file") or Multilink("file") property using links that
413 allow you to download files
414 '''
415 if not nodeid:
416 return _('[Download: not called from item]')
417 return do_link(client, classname, cl, props, nodeid, filterspec, property, is_download=1)
418
419
420 def do_checklist(client, classname, cl, props, nodeid, filterspec, property, sortby=None):
421 ''' for a Link or Multilink property, display checkboxes for the
422 available choices to permit filtering
423
424 sort the checklist by the argument (+/- property name)
425 '''
426 propclass = props[property]
427 if (not isinstance(propclass, hyperdb.Link) and not
428 isinstance(propclass, hyperdb.Multilink)):
429 return _('[Checklist: not a link]')
430
431 # get our current checkbox state
432 if nodeid:
433 # get the info from the node - make sure it's a list
434 if isinstance(propclass, hyperdb.Link):
435 value = [cl.get(nodeid, property)]
436 else:
437 value = cl.get(nodeid, property)
438 elif filterspec is not None:
439 # get the state from the filter specification (always a list)
440 value = filterspec.get(property, [])
441 else:
442 # it's a new node, so there's no state
443 value = []
444
445 # so we can map to the linked node's "lable" property
446 linkcl = client.db.getclass(propclass.classname)
447 l = []
448 k = linkcl.labelprop(1)
449
450 # build list of options and then sort it, either
451 # by id + label or <sortby>-value + label;
452 # a minus reverses the sort order, while + or no
453 # prefix sort in increasing order
454 reversed = 0
455 if sortby:
456 if sortby[0] == '-':
457 reversed = 1
458 sortby = sortby[1:]
459 elif sortby[0] == '+':
460 sortby = sortby[1:]
461 options = []
462 for optionid in linkcl.list():
463 if sortby:
464 sortval = linkcl.get(optionid, sortby)
465 else:
466 sortval = int(optionid)
467 option = cgi.escape(str(linkcl.get(optionid, k)))
468 options.append((sortval, option, optionid))
469 options.sort()
470 if reversed:
471 options.reverse()
472
473 # build checkboxes
474 for sortval, option, optionid in options:
475 if optionid in value or option in value:
476 checked = 'checked'
477 else:
478 checked = ''
479 l.append('%s:<input type="checkbox" %s name="%s" value="%s">'%(
480 option, checked, property, option))
481
482 # for Links, allow the "unselected" option too
483 if isinstance(propclass, hyperdb.Link):
484 if value is None or '-1' in value:
485 checked = 'checked'
486 else:
487 checked = ''
488 l.append(_('[unselected]:<input type="checkbox" %s name="%s" '
489 'value="-1">')%(checked, property))
490 return '\n'.join(l)
491
492 def do_note(client, classname, cl, props, nodeid, filterspec, rows=5, cols=80):
493 ''' display a "note" field, which is a text area for entering a note to
494 go along with a change.
495 '''
496 # TODO: pull the value from the form
497 return '<textarea name="__note" wrap="hard" rows=%s cols=%s>'\
498 '</textarea>'%(rows, cols)
499
500 # XXX new function
501 def do_list(client, classname, cl, props, nodeid, filterspec, property, reverse=0, xtracols=None):
502 ''' list the items specified by property using the standard index for
503 the class
504 '''
505 propcl = props[property]
506 if not isinstance(propcl, hyperdb.Multilink):
507 return _('[List: not a Multilink]')
508
509 value = determine_value(cl, props, nodeid, filterspec, property)
510 if not value:
511 return ''
512
513 # sort, possibly revers and then re-stringify
514 value = map(int, value)
515 value.sort()
516 if reverse:
517 value.reverse()
518 value = map(str, value)
519
520 # render the sub-index into a string
521 fp = StringIO.StringIO()
522 try:
523 write_save = client.write
524 client.write = fp.write
525 client.listcontext = ('%s%s' % (classname, nodeid), property)
526 index = htmltemplate.IndexTemplate(client, client.instance.TEMPLATES, propcl.classname)
527 index.render(nodeids=value, show_display_form=0, xtracols=xtracols)
528 finally:
529 client.listcontext = None
530 client.write = write_save
531
532 return fp.getvalue()
533
534 # XXX new function
535 def do_history(client, classname, cl, props, nodeid, filterspec, direction='descending'):
536 ''' list the history of the item
537
538 If "direction" is 'descending' then the most recent event will
539 be displayed first. If it is 'ascending' then the oldest event
540 will be displayed first.
541 '''
542 if nodeid is None:
543 return _("[History: node doesn't exist]")
544
545 l = ['<table width=100% border=0 cellspacing=0 cellpadding=2>',
546 '<tr class="list-header">',
547 _('<th align=left><span class="list-item">Date</span></th>'),
548 _('<th align=left><span class="list-item">User</span></th>'),
549 _('<th align=left><span class="list-item">Action</span></th>'),
550 _('<th align=left><span class="list-item">Args</span></th>'),
551 '</tr>']
552 comments = {}
553 history = cl.history(nodeid)
554 history.sort()
555 if direction == 'descending':
556 history.reverse()
557 for id, evt_date, user, action, args in history:
558 date_s = str(evt_date).replace("."," ")
559 arg_s = ''
560 if action == 'link' and type(args) == type(()):
561 if len(args) == 3:
562 linkcl, linkid, key = args
563 arg_s += '<a href="%s%s">%s%s %s</a>'%(linkcl, linkid,
564 linkcl, linkid, key)
565 else:
566 arg_s = str(args)
567
568 elif action == 'unlink' and type(args) == type(()):
569 if len(args) == 3:
570 linkcl, linkid, key = args
571 arg_s += '<a href="%s%s">%s%s %s</a>'%(linkcl, linkid,
572 linkcl, linkid, key)
573 else:
574 arg_s = str(args)
575
576 elif type(args) == type({}):
577 cell = []
578 for k in args.keys():
579 # try to get the relevant property and treat it
580 # specially
581 try:
582 prop = props[k]
583 except:
584 prop = None
585 if prop is not None:
586 if args[k] and (isinstance(prop, hyperdb.Multilink) or
587 isinstance(prop, hyperdb.Link)):
588 # figure what the link class is
589 classname = prop.classname
590 try:
591 linkcl = client.db.getclass(classname)
592 except KeyError:
593 labelprop = None
594 comments[classname] = _('''The linked class
595 %(classname)s no longer exists''')%locals()
596 labelprop = linkcl.labelprop(1)
597 hrefable = os.path.exists(
598 os.path.join(client.instance.TEMPLATES, classname+'.item'))
599
600 if isinstance(prop, hyperdb.Multilink) and \
601 len(args[k]) > 0:
602 ml = []
603 for linkid in args[k]:
604 label = classname + linkid
605 # if we have a label property, try to use it
606 # TODO: test for node existence even when
607 # there's no labelprop!
608 try:
609 if labelprop is not None:
610 label = linkcl.get(linkid, labelprop)
611 except IndexError:
612 comments['no_link'] = _('''<strike>The
613 linked node no longer
614 exists</strike>''')
615 ml.append('<strike>%s</strike>'%label)
616 else:
617 if hrefable:
618 ml.append('<a href="%s%s">%s</a>'%(
619 classname, linkid, label))
620 else:
621 ml.append(label)
622 cell.append('%s:\n %s'%(k, ',\n '.join(ml)))
623 elif isinstance(prop, hyperdb.Link) and args[k]:
624 label = classname + args[k]
625 # if we have a label property, try to use it
626 # TODO: test for node existence even when
627 # there's no labelprop!
628 if labelprop is not None:
629 try:
630 label = linkcl.get(args[k], labelprop)
631 except IndexError:
632 comments['no_link'] = _('''<strike>The
633 linked node no longer
634 exists</strike>''')
635 cell.append(' <strike>%s</strike>,\n'%label)
636 # "flag" this is done .... euwww
637 label = None
638 if label is not None:
639 if hrefable:
640 cell.append('%s: <a href="%s%s">%s</a>\n'%(k,
641 classname, args[k], label))
642 else:
643 cell.append('%s: %s' % (k,label))
644
645 elif isinstance(prop, hyperdb.Date) and args[k]:
646 d = date.Date(args[k])
647 cell.append('%s: %s'%(k, str(d)))
648
649 elif isinstance(prop, hyperdb.Interval) and args[k]:
650 d = date.Interval(args[k])
651 cell.append('%s: %s'%(k, str(d)))
652
653 elif isinstance(prop, hyperdb.String) and args[k]:
654 cell.append('%s: %s'%(k, cgi.escape(args[k])))
655
656 elif not args[k]:
657 cell.append('%s: (no value)\n'%k)
658
659 else:
660 cell.append('%s: %s\n'%(k, str(args[k])))
661 else:
662 # property no longer exists
663 comments['no_exist'] = _('''<em>The indicated property
664 no longer exists</em>''')
665 cell.append('<em>%s: %s</em>\n'%(k, str(args[k])))
666 arg_s = '<br />'.join(cell)
667 else:
668 # unkown event!!
669 comments['unknown'] = _('''<strong><em>This event is not
670 handled by the history display!</em></strong>''')
671 arg_s = '<strong><em>' + str(args) + '</em></strong>'
672 date_s = date_s.replace(' ', '&nbsp;')
673 l.append('<tr><td nowrap valign=top>%s</td><td valign=top>%s</td>'
674 '<td valign=top>%s</td><td valign=top>%s</td></tr>'%(date_s,
675 user, action, arg_s))
676 if comments:
677 l.append(_('<tr><td colspan=4><strong>Note:</strong></td></tr>'))
678 for entry in comments.values():
679 l.append('<tr><td colspan=4>%s</td></tr>'%entry)
680 l.append('</table>')
681 return '\n'.join(l)
682
683 # XXX new function
684 def do_submit(client, classname, cl, props, nodeid, filterspec, value=None):
685 ''' add a submit button for the item
686 '''
687 if value is None:
688 if nodeid:
689 value = "Submit Changes"
690 else:
691 value = "Submit New Entry"
692 if nodeid or client.form is not None:
693 return _('<input type="submit" name="submit" value="%s">' % value)
694 else:
695 return _('[Submit: not called from item]')
696
697 def do_classhelp(client, classname, cl, props, nodeid, filterspec, clname, properties, label='?', width='400',
698 height='400'):
699 '''pop up a javascript window with class help
700
701 This generates a link to a popup window which displays the
702 properties indicated by "properties" of the class named by
703 "classname". The "properties" should be a comma-separated list
704 (eg. 'id,name,description').
705
706 You may optionally override the label displayed, the width and
707 height. The popup window will be resizable and scrollable.
708 '''
709 return '<a href="javascript:help_window(\'classhelp?classname=%s&' \
710 'properties=%s\', \'%s\', \'%s\')"><b>(%s)</b></a>'%(clname,
711 properties, width, height, label)
712
713 def do_email(client, classname, cl, props, nodeid, filterspec, property, escape=0):
714 '''display the property as one or more "fudged" email addrs
715 '''
716
717 if not nodeid and client.form is None:
718 return _('[Email: not called from item]')
719 propclass = props[property]
720 if nodeid:
721 # get the value for this property
722 try:
723 value = cl.get(nodeid, property)
724 except KeyError:
725 # a KeyError here means that the node doesn't have a value
726 # for the specified property
727 value = ''
728 else:
729 value = ''
730 if isinstance(propclass, hyperdb.String):
731 if value is None: value = ''
732 else: value = str(value)
733 value = value.replace('@', ' at ')
734 value = value.replace('.', ' ')
735 else:
736 value = _('[Email: not a string]')%locals()
737 if escape:
738 value = cgi.escape(value)
739 return value
740
741 def do_filterspec(client, classname, cl, props, nodeid, filterspec, classprop, urlprop):
742 qs = cl.get(nodeid, urlprop)
743 classname = cl.get(nodeid, classprop)
744 filterspec = {}
745 query = cgi.parse_qs(qs)
746 for k,v in query.items():
747 query[k] = v[0].split(',')
748 pagesize = query.get(':pagesize',['25'])[0]
749 search_text = query.get('search_text', [''])[0]
750 search_text = urllib.unquote(search_text)
751 for k,v in query.items():
752 if k[0] != ':':
753 filterspec[k] = v
754 ixtmplt = htmltemplate.IndexTemplate(client, client.instance.TEMPLATES, classname)
755 qform = '<form onSubmit="return submit_once()" action="%s%s">\n'%(
756 classname,nodeid)
757 qform += ixtmplt.filter_form(search_text,
758 query.get(':filter', []),
759 query.get(':columns', []),
760 query.get(':group', []),
761 [],
762 query.get(':sort',[]),
763 filterspec,
764 pagesize)
765 return qform + '</table>\n'
766
767 def do_href(client, classname, cl, props, nodeid, filterspec, property, prefix='', suffix='', label=''):
768 value = determine_value(cl, props, nodeid, filterspec, property)
769 return '<a href="%s%s%s">%s</a>' % (prefix, value, suffix, label)
770
771 def do_remove(client, classname, cl, props, nodeid, filterspec):
772 ''' put a remove href for an item in a list '''
773 if not nodeid:
774 return _('[Remove not called from item]')
775 try:
776 parentdesignator, mlprop = client.listcontext
777 except (AttributeError, TypeError):
778 return _('[Remove not called form listing of multilink]')
779 return '<a href="remove?:target=%s%s&:multilink=%s:%s">[Remove]</a>' % (classname, nodeid, parentdesignator, mlprop)
780
781
782

Roundup Issue Tracker: http://roundup-tracker.org/