1 #
2 # $Id: template_funcs.py,v 1.3 2002-08-19 00:22:47 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 if isinstance(linkid, type(())):
622 sublabel = linkid[0] + ' '
623 linkids = linkid[1]
624 else:
625 sublabel = ''
626 linkids = [linkid]
627 subml = []
628 for linkid in linkids:
629 label = classname + linkid
630 # if we have a label property, try to use it
631 # TODO: test for node existence even when
632 # there's no labelprop!
633 try:
634 if labelprop is not None:
635 label = linkcl.get(linkid, labelprop)
636 except IndexError:
637 comments['no_link'] = _('''<strike>The
638 linked node no longer
639 exists</strike>''')
640 subml.append('<strike>%s</strike>'%label)
641 else:
642 if hrefable:
643 subml.append('<a href="%s%s">%s</a>'%(
644 classname, linkid, label))
645 else:
646 subml.append(label)
647 ml.append(sublabel + ', '.join(subml))
648 cell.append('%s:\n %s'%(k, ', '.join(ml)))
649 elif isinstance(prop, hyperdb.Link) and args[k]:
650 label = classname + args[k]
651 # if we have a label property, try to use it
652 # TODO: test for node existence even when
653 # there's no labelprop!
654 if labelprop is not None:
655 try:
656 label = linkcl.get(args[k], labelprop)
657 except IndexError:
658 comments['no_link'] = _('''<strike>The
659 linked node no longer
660 exists</strike>''')
661 cell.append(' <strike>%s</strike>,\n'%label)
662 # "flag" this is done .... euwww
663 label = None
664 if label is not None:
665 if hrefable:
666 cell.append('%s: <a href="%s%s">%s</a>\n'%(k,
667 classname, args[k], label))
668 else:
669 cell.append('%s: %s' % (k,label))
671 elif isinstance(prop, hyperdb.Date) and args[k]:
672 d = date.Date(args[k])
673 cell.append('%s: %s'%(k, str(d)))
675 elif isinstance(prop, hyperdb.Interval) and args[k]:
676 d = date.Interval(args[k])
677 cell.append('%s: %s'%(k, str(d)))
679 elif isinstance(prop, hyperdb.String) and args[k]:
680 cell.append('%s: %s'%(k, cgi.escape(args[k])))
682 elif not args[k]:
683 cell.append('%s: (no value)\n'%k)
685 else:
686 cell.append('%s: %s\n'%(k, str(args[k])))
687 else:
688 # property no longer exists
689 comments['no_exist'] = _('''<em>The indicated property
690 no longer exists</em>''')
691 cell.append('<em>%s: %s</em>\n'%(k, str(args[k])))
692 arg_s = '<br />'.join(cell)
693 else:
694 # unkown event!!
695 comments['unknown'] = _('''<strong><em>This event is not
696 handled by the history display!</em></strong>''')
697 arg_s = '<strong><em>' + str(args) + '</em></strong>'
698 date_s = date_s.replace(' ', ' ')
699 l.append('<tr><td nowrap valign=top>%s</td><td valign=top>%s</td>'
700 '<td valign=top>%s</td><td valign=top>%s</td></tr>'%(date_s,
701 user, action, arg_s))
702 if comments:
703 l.append(_('<tr><td colspan=4><strong>Note:</strong></td></tr>'))
704 for entry in comments.values():
705 l.append('<tr><td colspan=4>%s</td></tr>'%entry)
706 l.append('</table>')
707 return '\n'.join(l)
709 # XXX new function
710 def do_submit(client, classname, cl, props, nodeid, filterspec, value=None):
711 ''' add a submit button for the item
712 '''
713 if value is None:
714 if nodeid:
715 value = "Submit Changes"
716 else:
717 value = "Submit New Entry"
718 if nodeid or client.form is not None:
719 return _('<input type="submit" name="submit" value="%s">' % value)
720 else:
721 return _('[Submit: not called from item]')
723 def do_classhelp(client, classname, cl, props, nodeid, filterspec, clname,
724 properties, label='?', width='400', height='400'):
725 '''pop up a javascript window with class help
727 This generates a link to a popup window which displays the
728 properties indicated by "properties" of the class named by
729 "classname". The "properties" should be a comma-separated list
730 (eg. 'id,name,description').
732 You may optionally override the label displayed, the width and
733 height. The popup window will be resizable and scrollable.
734 '''
735 return '<a href="javascript:help_window(\'classhelp?classname=%s&' \
736 'properties=%s\', \'%s\', \'%s\')"><b>(%s)</b></a>'%(clname,
737 properties, width, height, label)
739 def do_email(client, classname, cl, props, nodeid, filterspec, property,
740 escape=0):
741 '''display the property as one or more "fudged" email addrs
742 '''
744 if not nodeid and client.form is None:
745 return _('[Email: not called from item]')
746 propclass = props[property]
747 if nodeid:
748 # get the value for this property
749 try:
750 value = cl.get(nodeid, property)
751 except KeyError:
752 # a KeyError here means that the node doesn't have a value
753 # for the specified property
754 value = ''
755 else:
756 value = ''
757 if isinstance(propclass, hyperdb.String):
758 if value is None: value = ''
759 else: value = str(value)
760 value = value.replace('@', ' at ')
761 value = value.replace('.', ' ')
762 else:
763 value = _('[Email: not a string]')%locals()
764 if escape:
765 value = cgi.escape(value)
766 return value
768 def do_filterspec(client, classname, cl, props, nodeid, filterspec, classprop,
769 urlprop):
771 qs = cl.get(nodeid, urlprop)
772 classname = cl.get(nodeid, classprop)
773 filterspec = {}
774 query = cgi.parse_qs(qs)
775 for k,v in query.items():
776 query[k] = v[0].split(',')
777 pagesize = query.get(':pagesize',['25'])[0]
778 search_text = query.get('search_text', [''])[0]
779 search_text = urllib.unquote(search_text)
780 for k,v in query.items():
781 if k[0] != ':':
782 filterspec[k] = v
783 ixtmplt = htmltemplate.IndexTemplate(client, client.instance.TEMPLATES,
784 classname)
785 qform = '<form onSubmit="return submit_once()" action="%s%s">\n'%(
786 classname,nodeid)
787 qform += ixtmplt.filter_form(search_text,
788 query.get(':filter', []),
789 query.get(':columns', []),
790 query.get(':group', []),
791 [],
792 query.get(':sort',[]),
793 filterspec,
794 pagesize)
795 return qform + '</table>\n'
797 def do_href(client, classname, cl, props, nodeid, filterspec, property,
798 prefix='', suffix='', label=''):
799 ''' Generate a link to the value of the property, with the form:
801 <a href="[prefix][value][suffix]">[label]</a>
803 where the [value] is the specified property value.
804 '''
805 value = determine_value(cl, props, nodeid, filterspec, property)
806 return '<a href="%s%s%s">%s</a>'%(prefix, value, suffix, label)
808 def do_remove(client, classname, cl, props, nodeid, filterspec):
809 ''' put a remove href for an item in a list '''
810 if not nodeid:
811 return _('[Remove not called from item]')
812 try:
813 parentdesignator, mlprop = client.listcontext
814 except (AttributeError, TypeError):
815 return _('[Remove not called form listing of multilink]')
816 return '<a href="remove?:target=%s%s&:multilink=%s:%s">[Remove]</a>'%(
817 classname, nodeid, parentdesignator, mlprop)
819 #
820 # $Log: not supported by cvs2svn $
821 # Revision 1.2 2002/08/15 00:40:10 richard
822 # cleanup
823 #
824 #
825 #
826 # vim: set filetype=python ts=4 sw=4 et si