Mercurial > p > roundup > code
comparison roundup/cgi/templating.py @ 1952:c40ed9113285
Applied Stefan Seefeld's html4/xhtml patch with some changes.
| author | Richard Jones <richard@users.sourceforge.net> |
|---|---|
| date | Sat, 06 Dec 2003 00:00:54 +0000 |
| parents | cd7af2579d20 |
| children | 1e2cccf6b53b |
comparison
equal
deleted
inserted
replaced
| 1951:767ff2a03eee | 1952:c40ed9113285 |
|---|---|
| 21 # bring in the templating support | 21 # bring in the templating support |
| 22 from roundup.cgi.PageTemplates import PageTemplate | 22 from roundup.cgi.PageTemplates import PageTemplate |
| 23 from roundup.cgi.PageTemplates.Expressions import getEngine | 23 from roundup.cgi.PageTemplates.Expressions import getEngine |
| 24 from roundup.cgi.TAL.TALInterpreter import TALInterpreter | 24 from roundup.cgi.TAL.TALInterpreter import TALInterpreter |
| 25 from roundup.cgi import ZTUtils | 25 from roundup.cgi import ZTUtils |
| 26 | |
| 27 def input_html4(**attrs): | |
| 28 """Generate an 'input' (html4) element with given attributes""" | |
| 29 return '<input %s>'%' '.join(['%s="%s"'%item for item in attrs.items()]) | |
| 30 | |
| 31 def input_xhtml(**attrs): | |
| 32 """Generate an 'input' (xhtml) element with given attributes""" | |
| 33 return '<input %s/>'%' '.join(['%s="%s"'%item for item in attrs.items()]) | |
| 26 | 34 |
| 27 class NoTemplate(Exception): | 35 class NoTemplate(Exception): |
| 28 pass | 36 pass |
| 29 | 37 |
| 30 def find_template(dir, name, extension): | 38 def find_template(dir, name, extension): |
| 293 # consistent API for extending Class/Item | 301 # consistent API for extending Class/Item |
| 294 self._classname = self.classname = classname | 302 self._classname = self.classname = classname |
| 295 self._klass = self._db.getclass(self.classname) | 303 self._klass = self._db.getclass(self.classname) |
| 296 self._props = self._klass.getprops() | 304 self._props = self._klass.getprops() |
| 297 | 305 |
| 306 html_version = 'html4' | |
| 307 if hasattr(self._client.instance.config, 'HTML_VERSION'): | |
| 308 html_version = self._client.instance.config.HTML_VERSION | |
| 309 if html_version == 'xhtml': | |
| 310 self.input = input_xhtml | |
| 311 else: | |
| 312 self.input = input_html4 | |
| 313 | |
| 298 def __repr__(self): | 314 def __repr__(self): |
| 299 return '<HTMLClass(0x%x) %s>'%(id(self), self.classname) | 315 return '<HTMLClass(0x%x) %s>'%(id(self), self.classname) |
| 300 | 316 |
| 301 def __getitem__(self, item): | 317 def __getitem__(self, item): |
| 302 ''' return an HTMLProperty instance | 318 ''' return an HTMLProperty instance |
| 476 height, label) | 492 height, label) |
| 477 | 493 |
| 478 def submit(self, label="Submit New Entry"): | 494 def submit(self, label="Submit New Entry"): |
| 479 ''' Generate a submit button (and action hidden element) | 495 ''' Generate a submit button (and action hidden element) |
| 480 ''' | 496 ''' |
| 481 return ' <input type="hidden" name="@action" value="new">\n'\ | 497 return self.input(type="hidden",name="@action",value="new") + '\n' + \ |
| 482 ' <input type="submit" name="submit" value="%s">'%label | 498 self.input(type="submit",name="submit",value=label) |
| 483 | 499 |
| 484 def history(self): | 500 def history(self): |
| 485 return 'New node - no history' | 501 return 'New node - no history' |
| 486 | 502 |
| 487 def renderWith(self, name, **kwargs): | 503 def renderWith(self, name, **kwargs): |
| 554 return '%s%s'%(self._classname, self._nodeid) | 570 return '%s%s'%(self._classname, self._nodeid) |
| 555 | 571 |
| 556 def submit(self, label="Submit Changes"): | 572 def submit(self, label="Submit Changes"): |
| 557 ''' Generate a submit button (and action hidden element) | 573 ''' Generate a submit button (and action hidden element) |
| 558 ''' | 574 ''' |
| 559 return ' <input type="hidden" name="@action" value="edit">\n'\ | 575 return self.input(type="hidden",name="@action",value="edit") + '\n' + \ |
| 560 ' <input type="submit" name="submit" value="%s">'%label | 576 self.input(type="submit",name="submit",value=label) |
| 561 | 577 |
| 562 def journal(self, direction='descending'): | 578 def journal(self, direction='descending'): |
| 563 ''' Return a list of HTMLJournalEntry instances. | 579 ''' Return a list of HTMLJournalEntry instances. |
| 564 ''' | 580 ''' |
| 565 # XXX do this | 581 # XXX do this |
| 842 self._name = name | 858 self._name = name |
| 843 if not anonymous: | 859 if not anonymous: |
| 844 self._formname = '%s%s@%s'%(classname, nodeid, name) | 860 self._formname = '%s%s@%s'%(classname, nodeid, name) |
| 845 else: | 861 else: |
| 846 self._formname = name | 862 self._formname = name |
| 863 | |
| 864 html_version = 'html4' | |
| 865 if hasattr(self._client.instance.config, 'HTML_VERSION'): | |
| 866 html_version = self._client.instance.config.HTML_VERSION | |
| 867 if html_version == 'xhtml': | |
| 868 self.input = input_xhtml | |
| 869 else: | |
| 870 self.input = input_html4 | |
| 871 | |
| 847 def __repr__(self): | 872 def __repr__(self): |
| 848 return '<HTMLProperty(0x%x) %s %r %r>'%(id(self), self._formname, | 873 return '<HTMLProperty(0x%x) %s %r %r>'%(id(self), self._formname, |
| 849 self._prop, self._value) | 874 self._prop, self._value) |
| 850 def __str__(self): | 875 def __str__(self): |
| 851 return self.plain() | 876 return self.plain() |
| 916 if self._value is None: | 941 if self._value is None: |
| 917 value = '' | 942 value = '' |
| 918 else: | 943 else: |
| 919 value = cgi.escape(str(self._value)) | 944 value = cgi.escape(str(self._value)) |
| 920 value = '"'.join(value.split('"')) | 945 value = '"'.join(value.split('"')) |
| 921 return '<input name="%s" value="%s" size="%s">'%(self._formname, value, size) | 946 return self.input(name=self._formname,value=value,size=size) |
| 922 | 947 |
| 923 def multiline(self, escape=0, rows=5, cols=40): | 948 def multiline(self, escape=0, rows=5, cols=40): |
| 924 ''' Render a multiline form edit field for the property | 949 ''' Render a multiline form edit field for the property |
| 925 ''' | 950 ''' |
| 926 if self._value is None: | 951 if self._value is None: |
| 956 return _('*encrypted*') | 981 return _('*encrypted*') |
| 957 | 982 |
| 958 def field(self, size = 30): | 983 def field(self, size = 30): |
| 959 ''' Render a form edit field for the property. | 984 ''' Render a form edit field for the property. |
| 960 ''' | 985 ''' |
| 961 return '<input type="password" name="%s" size="%s">'%(self._formname, size) | 986 return self.input(type="password", name=self._formname, size=size) |
| 962 | 987 |
| 963 def confirm(self, size = 30): | 988 def confirm(self, size = 30): |
| 964 ''' Render a second form edit field for the property, used for | 989 ''' Render a second form edit field for the property, used for |
| 965 confirmation that the user typed the password correctly. Generates | 990 confirmation that the user typed the password correctly. Generates |
| 966 a field with name "@confirm@name". | 991 a field with name "@confirm@name". |
| 967 ''' | 992 ''' |
| 968 return '<input type="password" name="@confirm@%s" size="%s">'%( | 993 return self.input(type="password", name="@confirm@%s"%self._formname, |
| 969 self._formname, size) | 994 size=size) |
| 970 | 995 |
| 971 class NumberHTMLProperty(HTMLProperty): | 996 class NumberHTMLProperty(HTMLProperty): |
| 972 def plain(self): | 997 def plain(self): |
| 973 ''' Render a "plain" representation of the property | 998 ''' Render a "plain" representation of the property |
| 974 ''' | 999 ''' |
| 980 if self._value is None: | 1005 if self._value is None: |
| 981 value = '' | 1006 value = '' |
| 982 else: | 1007 else: |
| 983 value = cgi.escape(str(self._value)) | 1008 value = cgi.escape(str(self._value)) |
| 984 value = '"'.join(value.split('"')) | 1009 value = '"'.join(value.split('"')) |
| 985 return '<input name="%s" value="%s" size="%s">'%(self._formname, value, size) | 1010 return self.input(name=self._formname,value=value,size=size) |
| 986 | 1011 |
| 987 def __int__(self): | 1012 def __int__(self): |
| 988 ''' Return an int of me | 1013 ''' Return an int of me |
| 989 ''' | 1014 ''' |
| 990 return int(self._value) | 1015 return int(self._value) |
| 1005 | 1030 |
| 1006 def field(self): | 1031 def field(self): |
| 1007 ''' Render a form edit field for the property | 1032 ''' Render a form edit field for the property |
| 1008 ''' | 1033 ''' |
| 1009 checked = self._value and "checked" or "" | 1034 checked = self._value and "checked" or "" |
| 1010 s = '<input type="radio" name="%s" value="yes" %s>Yes'%(self._formname, | 1035 if self._value: |
| 1011 checked) | 1036 s = self.input(type="radio",name=self._formname,value="yes",checked="checked") |
| 1012 if checked: | 1037 s += 'Yes' |
| 1013 checked = "" | 1038 s +=self.input(type="radio",name=self._formname,value="no") |
| 1014 else: | 1039 s += 'No' |
| 1015 checked = "checked" | 1040 else: |
| 1016 s += '<input type="radio" name="%s" value="no" %s>No'%(self._formname, | 1041 s = self.input(type="radio",name=self._formname,value="yes") |
| 1017 checked) | 1042 s += 'Yes' |
| 1043 s +=self.input(type="radio",name=self._formname,value="no",checked="checked") | |
| 1044 s += 'No' | |
| 1018 return s | 1045 return s |
| 1019 | 1046 |
| 1020 class DateHTMLProperty(HTMLProperty): | 1047 class DateHTMLProperty(HTMLProperty): |
| 1021 def plain(self): | 1048 def plain(self): |
| 1022 ''' Render a "plain" representation of the property | 1049 ''' Render a "plain" representation of the property |
| 1040 if self._value is None: | 1067 if self._value is None: |
| 1041 value = '' | 1068 value = '' |
| 1042 else: | 1069 else: |
| 1043 value = cgi.escape(str(self._value.local(self._db.getUserTimezone()))) | 1070 value = cgi.escape(str(self._value.local(self._db.getUserTimezone()))) |
| 1044 value = '"'.join(value.split('"')) | 1071 value = '"'.join(value.split('"')) |
| 1045 return '<input name="%s" value="%s" size="%s">'%(self._formname, value, size) | 1072 return self.input(name=self._formname,value=value,size=size) |
| 1046 | 1073 |
| 1047 def reldate(self, pretty=1): | 1074 def reldate(self, pretty=1): |
| 1048 ''' Render the interval between the date and now. | 1075 ''' Render the interval between the date and now. |
| 1049 | 1076 |
| 1050 If the "pretty" flag is true, then make the display pretty. | 1077 If the "pretty" flag is true, then make the display pretty. |
| 1097 if self._value is None: | 1124 if self._value is None: |
| 1098 value = '' | 1125 value = '' |
| 1099 else: | 1126 else: |
| 1100 value = cgi.escape(str(self._value)) | 1127 value = cgi.escape(str(self._value)) |
| 1101 value = '"'.join(value.split('"')) | 1128 value = '"'.join(value.split('"')) |
| 1102 return '<input name="%s" value="%s" size="%s">'%(self._formname, value, size) | 1129 return self.input(name=self._formname,value=value,size=size) |
| 1103 | 1130 |
| 1104 class LinkHTMLProperty(HTMLProperty): | 1131 class LinkHTMLProperty(HTMLProperty): |
| 1105 ''' Link HTMLProperty | 1132 ''' Link HTMLProperty |
| 1106 Include the above as well as being able to access the class | 1133 Include the above as well as being able to access the class |
| 1107 information. Stringifying the object itself results in the value | 1134 information. Stringifying the object itself results in the value |
| 1153 options = linkcl.filter(None, {}, ('+', sort_on), (None, None)) | 1180 options = linkcl.filter(None, {}, ('+', sort_on), (None, None)) |
| 1154 # TODO: make this a field display, not a menu one! | 1181 # TODO: make this a field display, not a menu one! |
| 1155 l = ['<select name="%s">'%self._formname] | 1182 l = ['<select name="%s">'%self._formname] |
| 1156 k = linkcl.labelprop(1) | 1183 k = linkcl.labelprop(1) |
| 1157 if self._value is None: | 1184 if self._value is None: |
| 1158 s = 'selected ' | 1185 s = 'selected="selected" ' |
| 1159 else: | 1186 else: |
| 1160 s = '' | 1187 s = '' |
| 1161 l.append(_('<option %svalue="-1">- no selection -</option>')%s) | 1188 l.append(_('<option %svalue="-1">- no selection -</option>')%s) |
| 1162 | 1189 |
| 1163 # make sure we list the current value if it's retired | 1190 # make sure we list the current value if it's retired |
| 1169 option = linkcl.get(optionid, k) or '' | 1196 option = linkcl.get(optionid, k) or '' |
| 1170 | 1197 |
| 1171 # figure if this option is selected | 1198 # figure if this option is selected |
| 1172 s = '' | 1199 s = '' |
| 1173 if optionid == self._value: | 1200 if optionid == self._value: |
| 1174 s = 'selected ' | 1201 s = 'selected="selected" ' |
| 1175 | 1202 |
| 1176 # figure the label | 1203 # figure the label |
| 1177 if showid: | 1204 if showid: |
| 1178 lab = '%s%s: %s'%(self._prop.classname, optionid, option) | 1205 lab = '%s%s: %s'%(self._prop.classname, optionid, option) |
| 1179 else: | 1206 else: |
| 1198 linkcl = self._db.getclass(self._prop.classname) | 1225 linkcl = self._db.getclass(self._prop.classname) |
| 1199 l = ['<select name="%s">'%self._formname] | 1226 l = ['<select name="%s">'%self._formname] |
| 1200 k = linkcl.labelprop(1) | 1227 k = linkcl.labelprop(1) |
| 1201 s = '' | 1228 s = '' |
| 1202 if value is None: | 1229 if value is None: |
| 1203 s = 'selected ' | 1230 s = 'selected="selected" ' |
| 1204 l.append(_('<option %svalue="-1">- no selection -</option>')%s) | 1231 l.append(_('<option %svalue="-1">- no selection -</option>')%s) |
| 1205 if linkcl.getprops().has_key('order'): | 1232 if linkcl.getprops().has_key('order'): |
| 1206 sort_on = ('+', 'order') | 1233 sort_on = ('+', 'order') |
| 1207 else: | 1234 else: |
| 1208 sort_on = ('+', linkcl.labelprop()) | 1235 sort_on = ('+', linkcl.labelprop()) |
| 1217 option = linkcl.get(optionid, k) or '' | 1244 option = linkcl.get(optionid, k) or '' |
| 1218 | 1245 |
| 1219 # figure if this option is selected | 1246 # figure if this option is selected |
| 1220 s = '' | 1247 s = '' |
| 1221 if value in [optionid, option]: | 1248 if value in [optionid, option]: |
| 1222 s = 'selected ' | 1249 s = 'selected="selected" ' |
| 1223 | 1250 |
| 1224 # figure the label | 1251 # figure the label |
| 1225 if showid: | 1252 if showid: |
| 1226 lab = '%s%s: %s'%(self._prop.classname, optionid, option) | 1253 lab = '%s%s: %s'%(self._prop.classname, optionid, option) |
| 1227 else: | 1254 else: |
| 1313 showid=1 | 1340 showid=1 |
| 1314 if not showid: | 1341 if not showid: |
| 1315 k = linkcl.labelprop(1) | 1342 k = linkcl.labelprop(1) |
| 1316 value = [linkcl.get(v, k) for v in value] | 1343 value = [linkcl.get(v, k) for v in value] |
| 1317 value = cgi.escape(','.join(value)) | 1344 value = cgi.escape(','.join(value)) |
| 1318 return '<input name="%s" size="%s" value="%s">'%(self._formname, size, value) | 1345 return self.input(name=self._formname,size=size,value=value) |
| 1319 | 1346 |
| 1320 def menu(self, size=None, height=None, showid=0, additional=[], | 1347 def menu(self, size=None, height=None, showid=0, additional=[], |
| 1321 **conditions): | 1348 **conditions): |
| 1322 ''' Render a form select list for this property | 1349 ''' Render a form select list for this property |
| 1323 ''' | 1350 ''' |
| 1340 option = linkcl.get(optionid, k) or '' | 1367 option = linkcl.get(optionid, k) or '' |
| 1341 | 1368 |
| 1342 # figure if this option is selected | 1369 # figure if this option is selected |
| 1343 s = '' | 1370 s = '' |
| 1344 if optionid in value or option in value: | 1371 if optionid in value or option in value: |
| 1345 s = 'selected ' | 1372 s = 'selected="selected" ' |
| 1346 | 1373 |
| 1347 # figure the label | 1374 # figure the label |
| 1348 if showid: | 1375 if showid: |
| 1349 lab = '%s%s: %s'%(self._prop.classname, optionid, option) | 1376 lab = '%s%s: %s'%(self._prop.classname, optionid, option) |
| 1350 else: | 1377 else: |
| 1448 self.classname = client.classname | 1475 self.classname = client.classname |
| 1449 self.template = client.template | 1476 self.template = client.template |
| 1450 | 1477 |
| 1451 # the special char to use for special vars | 1478 # the special char to use for special vars |
| 1452 self.special_char = '@' | 1479 self.special_char = '@' |
| 1480 | |
| 1481 html_version = 'html4' | |
| 1482 if hasattr(self.client.instance.config, 'HTML_VERSION'): | |
| 1483 html_version = self.client.instance.config.HTML_VERSION | |
| 1484 if html_version == 'xhtml': | |
| 1485 self.input = input_xhtml | |
| 1486 else: | |
| 1487 self.input = input_html4 | |
| 1453 | 1488 |
| 1454 self._post_init() | 1489 self._post_init() |
| 1455 | 1490 |
| 1456 def _post_init(self): | 1491 def _post_init(self): |
| 1457 ''' Set attributes based on self.form | 1492 ''' Set attributes based on self.form |
| 1601 def indexargs_form(self, columns=1, sort=1, group=1, filter=1, | 1636 def indexargs_form(self, columns=1, sort=1, group=1, filter=1, |
| 1602 filterspec=1): | 1637 filterspec=1): |
| 1603 ''' return the current index args as form elements ''' | 1638 ''' return the current index args as form elements ''' |
| 1604 l = [] | 1639 l = [] |
| 1605 sc = self.special_char | 1640 sc = self.special_char |
| 1606 s = '<input type="hidden" name="%s" value="%s">' | 1641 s = self.input(type="hidden",name="%s",value="%s") |
| 1607 if columns and self.columns: | 1642 if columns and self.columns: |
| 1608 l.append(s%(sc+'columns', ','.join(self.columns))) | 1643 l.append(s%(sc+'columns', ','.join(self.columns))) |
| 1609 if sort and self.sort[1] is not None: | 1644 if sort and self.sort[1] is not None: |
| 1610 if self.sort[0] == '-': | 1645 if self.sort[0] == '-': |
| 1611 val = '-'+self.sort[1] | 1646 val = '-'+self.sort[1] |
