Mercurial > p > roundup > code
comparison roundup/htmltemplate.py @ 651:6257d4e49d2a
Ran it through pychecker, made fixes
| author | Richard Jones <richard@users.sourceforge.net> |
|---|---|
| date | Wed, 27 Feb 2002 04:14:31 +0000 |
| parents | 7dd13fd5d8ea |
| children | d92e06a3a56e |
comparison
equal
deleted
inserted
replaced
| 650:9b2575610953 | 651:6257d4e49d2a |
|---|---|
| 13 # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | 13 # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
| 14 # FOR A PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" | 14 # FOR A PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" |
| 15 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, | 15 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, |
| 16 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | 16 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
| 17 # | 17 # |
| 18 # $Id: htmltemplate.py,v 1.82 2002-02-21 23:11:45 richard Exp $ | 18 # $Id: htmltemplate.py,v 1.83 2002-02-27 04:14:31 richard Exp $ |
| 19 | 19 |
| 20 __doc__ = """ | 20 __doc__ = """ |
| 21 Template engine. | 21 Template engine. |
| 22 """ | 22 """ |
| 23 | 23 |
| 24 import os, re, StringIO, urllib, cgi, errno, types | 24 import os, re, StringIO, urllib, cgi, errno, types |
| 25 | 25 |
| 26 import hyperdb, date, password | 26 import hyperdb, date |
| 27 from i18n import _ | 27 from i18n import _ |
| 28 | 28 |
| 29 # This imports the StructureText functionality for the do_stext function | 29 # This imports the StructureText functionality for the do_stext function |
| 30 # get it from http://dev.zope.org/Members/jim/StructuredTextWiki/NGReleases | 30 # get it from http://dev.zope.org/Members/jim/StructuredTextWiki/NGReleases |
| 31 try: | 31 try: |
| 32 from StructuredText.StructuredText import HTML as StructuredText | 32 from StructuredText.StructuredText import HTML as StructuredText |
| 33 except ImportError: | 33 except ImportError: |
| 34 StructuredText = None | 34 StructuredText = None |
| 35 | 35 |
| 36 class MissingTemplateError(ValueError): | 36 class MissingTemplateError(ValueError): |
| 37 '''Error raised when a template file is missing | |
| 38 ''' | |
| 37 pass | 39 pass |
| 38 | 40 |
| 39 class TemplateFunctions: | 41 class TemplateFunctions: |
| 42 '''Defines the templating functions that are used in the HTML templates | |
| 43 of the roundup web interface. | |
| 44 ''' | |
| 40 def __init__(self): | 45 def __init__(self): |
| 41 self.form = None | 46 self.form = None |
| 42 self.nodeid = None | 47 self.nodeid = None |
| 43 self.filterspec = None | 48 self.filterspec = None |
| 44 self.globals = {} | 49 self.globals = {} |
| 45 for key in TemplateFunctions.__dict__.keys(): | 50 for key in TemplateFunctions.__dict__.keys(): |
| 46 if key[:3] == 'do_': | 51 if key[:3] == 'do_': |
| 47 self.globals[key[3:]] = getattr(self, key) | 52 self.globals[key[3:]] = getattr(self, key) |
| 48 | 53 |
| 54 # These are added by the subclass where appropriate | |
| 55 self.client = None | |
| 56 self.instance = None | |
| 57 self.templates = None | |
| 58 self.classname = None | |
| 59 self.db = None | |
| 60 self.cl = None | |
| 61 self.properties = None | |
| 62 | |
| 49 def do_plain(self, property, escape=0): | 63 def do_plain(self, property, escape=0): |
| 50 ''' display a String property directly; | 64 ''' display a String property directly; |
| 51 | 65 |
| 52 display a Date property in a specified time zone with an option to | 66 display a Date property in a specified time zone with an option to |
| 53 omit the time from the date stamp; | 67 omit the time from the date stamp; |
| 59 return _('[Field: not called from item]') | 73 return _('[Field: not called from item]') |
| 60 propclass = self.properties[property] | 74 propclass = self.properties[property] |
| 61 if self.nodeid: | 75 if self.nodeid: |
| 62 # make sure the property is a valid one | 76 # make sure the property is a valid one |
| 63 # TODO: this tests, but we should handle the exception | 77 # TODO: this tests, but we should handle the exception |
| 64 prop_test = self.cl.getprops()[property] | 78 dummy = self.cl.getprops()[property] |
| 65 | 79 |
| 66 # get the value for this property | 80 # get the value for this property |
| 67 try: | 81 try: |
| 68 value = self.cl.get(self.nodeid, property) | 82 value = self.cl.get(self.nodeid, property) |
| 69 except KeyError: | 83 except KeyError: |
| 96 elif isinstance(propclass, hyperdb.Multilink): | 110 elif isinstance(propclass, hyperdb.Multilink): |
| 97 linkcl = self.db.classes[propclass.classname] | 111 linkcl = self.db.classes[propclass.classname] |
| 98 k = linkcl.labelprop() | 112 k = linkcl.labelprop() |
| 99 value = ', '.join(value) | 113 value = ', '.join(value) |
| 100 else: | 114 else: |
| 101 s = _('Plain: bad propclass "%(propclass)s"')%locals() | 115 value = _('Plain: bad propclass "%(propclass)s"')%locals() |
| 102 if escape: | 116 if escape: |
| 103 value = cgi.escape(value) | 117 value = cgi.escape(value) |
| 104 return value | 118 return value |
| 105 | 119 |
| 106 def do_stext(self, property, escape=0): | 120 def do_stext(self, property, escape=0): |
| 536 if len(args) == 3: | 550 if len(args) == 3: |
| 537 linkcl, linkid, key = args | 551 linkcl, linkid, key = args |
| 538 arg_s += '<a href="%s%s">%s%s %s</a>'%(linkcl, linkid, | 552 arg_s += '<a href="%s%s">%s%s %s</a>'%(linkcl, linkid, |
| 539 linkcl, linkid, key) | 553 linkcl, linkid, key) |
| 540 else: | 554 else: |
| 541 arg_s = str(arg) | 555 arg_s = str(args) |
| 542 | 556 |
| 543 elif action == 'unlink' and type(args) == type(()): | 557 elif action == 'unlink' and type(args) == type(()): |
| 544 if len(args) == 3: | 558 if len(args) == 3: |
| 545 linkcl, linkid, key = args | 559 linkcl, linkid, key = args |
| 546 arg_s += '<a href="%s%s">%s%s %s</a>'%(linkcl, linkid, | 560 arg_s += '<a href="%s%s">%s%s %s</a>'%(linkcl, linkid, |
| 547 linkcl, linkid, key) | 561 linkcl, linkid, key) |
| 548 else: | 562 else: |
| 549 arg_s = str(arg) | 563 arg_s = str(args) |
| 550 | 564 |
| 551 elif type(args) == type({}): | 565 elif type(args) == type({}): |
| 552 cell = [] | 566 cell = [] |
| 553 for k in args.keys(): | 567 for k in args.keys(): |
| 554 # try to get the relevant property and treat it | 568 # try to get the relevant property and treat it |
| 562 isinstance(prop, hyperdb.Link)): | 576 isinstance(prop, hyperdb.Link)): |
| 563 # figure what the link class is | 577 # figure what the link class is |
| 564 classname = prop.classname | 578 classname = prop.classname |
| 565 try: | 579 try: |
| 566 linkcl = self.db.classes[classname] | 580 linkcl = self.db.classes[classname] |
| 567 except KeyError, message: | 581 except KeyError: |
| 568 labelprop = None | 582 labelprop = None |
| 569 comments[classname] = _('''The linked class | 583 comments[classname] = _('''The linked class |
| 570 %(classname)s no longer exists''')%locals() | 584 %(classname)s no longer exists''')%locals() |
| 571 labelprop = linkcl.labelprop() | 585 labelprop = linkcl.labelprop() |
| 572 | 586 |
| 672 properties, width, height, label) | 686 properties, width, height, label) |
| 673 # | 687 # |
| 674 # INDEX TEMPLATES | 688 # INDEX TEMPLATES |
| 675 # | 689 # |
| 676 class IndexTemplateReplace: | 690 class IndexTemplateReplace: |
| 691 '''Regular-expression based parser that turns the template into HTML. | |
| 692 ''' | |
| 677 def __init__(self, globals, locals, props): | 693 def __init__(self, globals, locals, props): |
| 678 self.globals = globals | 694 self.globals = globals |
| 679 self.locals = locals | 695 self.locals = locals |
| 680 self.props = props | 696 self.props = props |
| 681 | 697 |
| 688 def __call__(self, m, filter=None, columns=None, sort=None, group=None): | 704 def __call__(self, m, filter=None, columns=None, sort=None, group=None): |
| 689 if m.group('name'): | 705 if m.group('name'): |
| 690 if m.group('name') in self.props: | 706 if m.group('name') in self.props: |
| 691 text = m.group('text') | 707 text = m.group('text') |
| 692 replace = IndexTemplateReplace(self.globals, {}, self.props) | 708 replace = IndexTemplateReplace(self.globals, {}, self.props) |
| 693 return replace.go(m.group('text')) | 709 return replace.go(text) |
| 694 else: | 710 else: |
| 695 return '' | 711 return '' |
| 696 if m.group('display'): | 712 if m.group('display'): |
| 697 command = m.group('command') | 713 command = m.group('command') |
| 698 return eval(command, self.globals, self.locals) | 714 return eval(command, self.globals, self.locals) |
| 699 print '*** unhandled match', m.groupdict() | 715 return '*** unhandled match: %s'%str(m.groupdict()) |
| 700 | 716 |
| 701 class IndexTemplate(TemplateFunctions): | 717 class IndexTemplate(TemplateFunctions): |
| 718 '''Templating functionality specifically for index pages | |
| 719 ''' | |
| 702 def __init__(self, client, templates, classname): | 720 def __init__(self, client, templates, classname): |
| 721 TemplateFunctions.__init__(self) | |
| 703 self.client = client | 722 self.client = client |
| 704 self.instance = client.instance | 723 self.instance = client.instance |
| 705 self.templates = templates | 724 self.templates = templates |
| 706 self.classname = classname | 725 self.classname = classname |
| 707 | 726 |
| 708 # derived | 727 # derived |
| 709 self.db = self.client.db | 728 self.db = self.client.db |
| 710 self.cl = self.db.classes[self.classname] | 729 self.cl = self.db.classes[self.classname] |
| 711 self.properties = self.cl.getprops() | 730 self.properties = self.cl.getprops() |
| 712 | |
| 713 TemplateFunctions.__init__(self) | |
| 714 | 731 |
| 715 col_re=re.compile(r'<property\s+name="([^>]+)">') | 732 col_re=re.compile(r'<property\s+name="([^>]+)">') |
| 716 def render(self, filterspec={}, filter=[], columns=[], sort=[], group=[], | 733 def render(self, filterspec={}, filter=[], columns=[], sort=[], group=[], |
| 717 show_display_form=1, nodeids=None, show_customization=1): | 734 show_display_form=1, nodeids=None, show_customization=1): |
| 718 self.filterspec = filterspec | 735 self.filterspec = filterspec |
| 934 w('</tr>\n') | 951 w('</tr>\n') |
| 935 | 952 |
| 936 # Grouping | 953 # Grouping |
| 937 w(_('<tr><th width="1%" align=right class="location-bar">Grouping</th>\n')) | 954 w(_('<tr><th width="1%" align=right class="location-bar">Grouping</th>\n')) |
| 938 for name in names: | 955 for name in names: |
| 939 prop = self.properties[name] | |
| 940 if name not in all_columns: | 956 if name not in all_columns: |
| 941 w('<td> </td>') | 957 w('<td> </td>') |
| 942 continue | 958 continue |
| 943 if name in group: checked=' checked' | 959 if name in group: checked=' checked' |
| 944 else: checked='' | 960 else: checked='' |
| 995 | 1011 |
| 996 # | 1012 # |
| 997 # ITEM TEMPLATES | 1013 # ITEM TEMPLATES |
| 998 # | 1014 # |
| 999 class ItemTemplateReplace: | 1015 class ItemTemplateReplace: |
| 1016 '''Regular-expression based parser that turns the template into HTML. | |
| 1017 ''' | |
| 1000 def __init__(self, globals, locals, cl, nodeid): | 1018 def __init__(self, globals, locals, cl, nodeid): |
| 1001 self.globals = globals | 1019 self.globals = globals |
| 1002 self.locals = locals | 1020 self.locals = locals |
| 1003 self.cl = cl | 1021 self.cl = cl |
| 1004 self.nodeid = nodeid | 1022 self.nodeid = nodeid |
| 1018 else: | 1036 else: |
| 1019 return '' | 1037 return '' |
| 1020 if m.group('display'): | 1038 if m.group('display'): |
| 1021 command = m.group('command') | 1039 command = m.group('command') |
| 1022 return eval(command, self.globals, self.locals) | 1040 return eval(command, self.globals, self.locals) |
| 1023 print '*** unhandled match', m.groupdict() | 1041 return '*** unhandled match: %s'%str(m.groupdict()) |
| 1024 | 1042 |
| 1025 | 1043 |
| 1026 class ItemTemplate(TemplateFunctions): | 1044 class ItemTemplate(TemplateFunctions): |
| 1045 '''Templating functionality specifically for item (node) display | |
| 1046 ''' | |
| 1027 def __init__(self, client, templates, classname): | 1047 def __init__(self, client, templates, classname): |
| 1048 TemplateFunctions.__init__(self) | |
| 1028 self.client = client | 1049 self.client = client |
| 1029 self.instance = client.instance | 1050 self.instance = client.instance |
| 1030 self.templates = templates | 1051 self.templates = templates |
| 1031 self.classname = classname | 1052 self.classname = classname |
| 1032 | 1053 |
| 1033 # derived | 1054 # derived |
| 1034 self.db = self.client.db | 1055 self.db = self.client.db |
| 1035 self.cl = self.db.classes[self.classname] | 1056 self.cl = self.db.classes[self.classname] |
| 1036 self.properties = self.cl.getprops() | 1057 self.properties = self.cl.getprops() |
| 1037 | |
| 1038 TemplateFunctions.__init__(self) | |
| 1039 | 1058 |
| 1040 def render(self, nodeid): | 1059 def render(self, nodeid): |
| 1041 self.nodeid = nodeid | 1060 self.nodeid = nodeid |
| 1042 | 1061 |
| 1043 if (self.properties.has_key('type') and | 1062 if (self.properties.has_key('type') and |
| 1055 w(replace.go(s)) | 1074 w(replace.go(s)) |
| 1056 w('</form>') | 1075 w('</form>') |
| 1057 | 1076 |
| 1058 | 1077 |
| 1059 class NewItemTemplate(TemplateFunctions): | 1078 class NewItemTemplate(TemplateFunctions): |
| 1079 '''Templating functionality specifically for NEW item (node) display | |
| 1080 ''' | |
| 1060 def __init__(self, client, templates, classname): | 1081 def __init__(self, client, templates, classname): |
| 1082 TemplateFunctions.__init__(self) | |
| 1061 self.client = client | 1083 self.client = client |
| 1062 self.instance = client.instance | 1084 self.instance = client.instance |
| 1063 self.templates = templates | 1085 self.templates = templates |
| 1064 self.classname = classname | 1086 self.classname = classname |
| 1065 | 1087 |
| 1066 # derived | 1088 # derived |
| 1067 self.db = self.client.db | 1089 self.db = self.client.db |
| 1068 self.cl = self.db.classes[self.classname] | 1090 self.cl = self.db.classes[self.classname] |
| 1069 self.properties = self.cl.getprops() | 1091 self.properties = self.cl.getprops() |
| 1070 | |
| 1071 TemplateFunctions.__init__(self) | |
| 1072 | 1092 |
| 1073 def render(self, form): | 1093 def render(self, form): |
| 1074 self.form = form | 1094 self.form = form |
| 1075 w = self.client.write | 1095 w = self.client.write |
| 1076 c = self.classname | 1096 c = self.classname |
| 1089 w(replace.go(s)) | 1109 w(replace.go(s)) |
| 1090 w('</form>') | 1110 w('</form>') |
| 1091 | 1111 |
| 1092 # | 1112 # |
| 1093 # $Log: not supported by cvs2svn $ | 1113 # $Log: not supported by cvs2svn $ |
| 1114 # Revision 1.82 2002/02/21 23:11:45 richard | |
| 1115 # . fixed some problems in date calculations (calendar.py doesn't handle over- | |
| 1116 # and under-flow). Also, hour/minute/second intervals may now be more than | |
| 1117 # 99 each. | |
| 1118 # | |
| 1094 # Revision 1.81 2002/02/21 07:21:38 richard | 1119 # Revision 1.81 2002/02/21 07:21:38 richard |
| 1095 # docco | 1120 # docco |
| 1096 # | 1121 # |
| 1097 # Revision 1.80 2002/02/21 07:19:08 richard | 1122 # Revision 1.80 2002/02/21 07:19:08 richard |
| 1098 # ... and label, width and height control for extra flavour! | 1123 # ... and label, width and height control for extra flavour! |
