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