Mercurial > p > roundup > code
comparison roundup/cgi/templating.py @ 7026:d7f0eab25305
flake8 E231 missing whitespace after ',' or ':'
| author | John Rouillard <rouilj@ieee.org> |
|---|---|
| date | Sun, 09 Oct 2022 17:51:42 -0400 |
| parents | 66149a18f09e |
| children | ab5e1fd920a1 |
comparison
equal
deleted
inserted
replaced
| 7025:66149a18f09e | 7026:d7f0eab25305 |
|---|---|
| 582 <input required ..> not <input required="required" ...> | 582 <input required ..> not <input required="required" ...> |
| 583 The latter is xhtml. Recognize booleans by: | 583 The latter is xhtml. Recognize booleans by: |
| 584 value is None | 584 value is None |
| 585 Code can use None to indicate a pure boolean. | 585 Code can use None to indicate a pure boolean. |
| 586 ''' | 586 ''' |
| 587 return ' '.join(['%s="%s"'%(k,html_escape(str(v), True)) | 587 return ' '.join(['%s="%s"'%(k, html_escape(str(v), True)) |
| 588 if v is not None else '%s'%(k) | 588 if v is not None else '%s'%(k) |
| 589 for k,v in sorted(attrs.items())]) | 589 for k, v in sorted(attrs.items())]) |
| 590 | 590 |
| 591 | 591 |
| 592 def xhtml_cgi_escape_attrs(**attrs): | 592 def xhtml_cgi_escape_attrs(**attrs): |
| 593 ''' Boolean attributes like 'disabled', 'required' | 593 ''' Boolean attributes like 'disabled', 'required' |
| 594 are represented with a value that is the same as | 594 are represented with a value that is the same as |
| 596 <input required="required" ...> not <input required ..> | 596 <input required="required" ...> not <input required ..> |
| 597 The latter is html4 or 5. Recognize booleans by: | 597 The latter is html4 or 5. Recognize booleans by: |
| 598 value is None | 598 value is None |
| 599 Code can use None to indicate a pure boolean. | 599 Code can use None to indicate a pure boolean. |
| 600 ''' | 600 ''' |
| 601 return ' '.join(['%s="%s"'%(k,html_escape(str(v), True)) | 601 return ' '.join(['%s="%s"'%(k, html_escape(str(v), True)) |
| 602 if v is not None else '%s="%s"'%(k,k) | 602 if v is not None else '%s="%s"'%(k, k) |
| 603 for k,v in sorted(attrs.items())]) | 603 for k, v in sorted(attrs.items())]) |
| 604 | 604 |
| 605 | 605 |
| 606 def input_html4(**attrs): | 606 def input_html4(**attrs): |
| 607 """Generate an 'input' (html4) element with given attributes""" | 607 """Generate an 'input' (html4) element with given attributes""" |
| 608 _set_input_default_args(attrs) | 608 _set_input_default_args(attrs) |
| 783 if isinstance(prop, klass): | 783 if isinstance(prop, klass): |
| 784 value = prop.get_default_value() | 784 value = prop.get_default_value() |
| 785 l.append(htmlklass(self._client, self._classname, '', | 785 l.append(htmlklass(self._client, self._classname, '', |
| 786 prop, name, value, self._anonymous)) | 786 prop, name, value, self._anonymous)) |
| 787 if sort: | 787 if sort: |
| 788 l.sort(key=lambda a:a._name) | 788 l.sort(key=lambda a: a._name) |
| 789 return l | 789 return l |
| 790 | 790 |
| 791 def list(self, sort_on=None): | 791 def list(self, sort_on=None): |
| 792 """ List all items in this class. | 792 """ List all items in this class. |
| 793 """ | 793 """ |
| 1158 timezone = self._db.getUserTimezone() | 1158 timezone = self._db.getUserTimezone() |
| 1159 l = [] | 1159 l = [] |
| 1160 current = {} | 1160 current = {} |
| 1161 comments = {} | 1161 comments = {} |
| 1162 for id, evt_date, user, action, args in history: | 1162 for id, evt_date, user, action, args in history: |
| 1163 date_s = str(evt_date.local(timezone)).replace("."," ") | 1163 date_s = str(evt_date.local(timezone)).replace(".", " ") |
| 1164 arg_s = '' | 1164 arg_s = '' |
| 1165 if action in ['link', 'unlink'] and isinstance(args, tuple): | 1165 if action in ['link', 'unlink'] and isinstance(args, tuple): |
| 1166 if len(args) == 3: | 1166 if len(args) == 3: |
| 1167 linkcl, linkid, key = args | 1167 linkcl, linkid, key = args |
| 1168 arg_s += '<a rel="nofollow noopener" href="%s%s">%s%s %s</a>'%(linkcl, linkid, | 1168 arg_s += '<a rel="nofollow noopener" href="%s%s">%s%s %s</a>'%(linkcl, linkid, |
| 1704 return '`%s <%s>`_'%(s, s) | 1704 return '`%s <%s>`_'%(s, s) |
| 1705 elif match.group('email'): | 1705 elif match.group('email'): |
| 1706 s = match.group('email') | 1706 s = match.group('email') |
| 1707 return '`%s <mailto:%s>`_'%(s, s) | 1707 return '`%s <mailto:%s>`_'%(s, s) |
| 1708 elif len(match.group('id')) < 10: | 1708 elif len(match.group('id')) < 10: |
| 1709 return self._hyper_repl_item(match,'`%(item)s <%(cls)s%(id)s>`_') | 1709 return self._hyper_repl_item(match, '`%(item)s <%(cls)s%(id)s>`_') |
| 1710 else: | 1710 else: |
| 1711 # just return the matched text | 1711 # just return the matched text |
| 1712 return match.group(0) | 1712 return match.group(0) |
| 1713 | 1713 |
| 1714 def _hyper_repl_markdown(self, match): | 1714 def _hyper_repl_markdown(self, match): |
| 1742 if end < len(match.string): | 1742 if end < len(match.string): |
| 1743 suffix = match.string[end] | 1743 suffix = match.string[end] |
| 1744 if (prefix, suffix) in {('[', ']')}: | 1744 if (prefix, suffix) in {('[', ']')}: |
| 1745 if match.string[end+1] == '(': # find following ( | 1745 if match.string[end+1] == '(': # find following ( |
| 1746 return match.group(0) | 1746 return match.group(0) |
| 1747 if (prefix, suffix) in {('(',')')}: | 1747 if (prefix, suffix) in {('(', ')')}: |
| 1748 if match.string[start-1] == ']': | 1748 if match.string[start-1] == ']': |
| 1749 return match.group(0) | 1749 return match.group(0) |
| 1750 return self._hyper_repl_item(match,'[%(item)s](%(cls)s%(id)s)') | 1750 return self._hyper_repl_item(match, '[%(item)s](%(cls)s%(id)s)') |
| 1751 else: | 1751 else: |
| 1752 # just return the matched text | 1752 # just return the matched text |
| 1753 return match.group(0) | 1753 return match.group(0) |
| 1754 | 1754 |
| 1755 def url_quote(self): | 1755 def url_quote(self): |
| 1820 return self._('[hidden]') | 1820 return self._('[hidden]') |
| 1821 | 1821 |
| 1822 s = self.plain(escape=escape, hyperlink=hyperlink) | 1822 s = self.plain(escape=escape, hyperlink=hyperlink) |
| 1823 if not StructuredText: | 1823 if not StructuredText: |
| 1824 return s | 1824 return s |
| 1825 return StructuredText(s,level=1,header=0) | 1825 return StructuredText(s, level=1, header=0) |
| 1826 | 1826 |
| 1827 def rst(self, hyperlink=1): | 1827 def rst(self, hyperlink=1): |
| 1828 """ Render the value of the property as ReStructuredText. | 1828 """ Render the value of the property as ReStructuredText. |
| 1829 | 1829 |
| 1830 This requires docutils to be installed separately. | 1830 This requires docutils to be installed separately. |
| 2339 "data-height": height | 2339 "data-height": height |
| 2340 } | 2340 } |
| 2341 | 2341 |
| 2342 return ('<a class="classhelp" %s href="javascript:help_window(' | 2342 return ('<a class="classhelp" %s href="javascript:help_window(' |
| 2343 "'%s?@template=calendar&property=%s&form=%s%s', %d, %d)" | 2343 "'%s?@template=calendar&property=%s&form=%s%s', %d, %d)" |
| 2344 '">%s</a>'%(self.cgi_escape_attrs(**data_attr),self._classname, self._name, form, date, width, | 2344 '">%s</a>'%(self.cgi_escape_attrs(**data_attr), |
| 2345 height, label)) | 2345 self._classname, self._name, form, date, width, |
| 2346 height, label)) | |
| 2346 | 2347 |
| 2347 | 2348 |
| 2348 class IntervalHTMLProperty(HTMLProperty): | 2349 class IntervalHTMLProperty(HTMLProperty): |
| 2349 def __init__(self, client, classname, nodeid, prop, name, value, | 2350 def __init__(self, client, classname, nodeid, prop, name, value, |
| 2350 anonymous=0): | 2351 anonymous=0): |
| 2676 """ | 2677 """ |
| 2677 | 2678 |
| 2678 # use 2 if NoneFirst is False to sort None last | 2679 # use 2 if NoneFirst is False to sort None last |
| 2679 # 0 to sort to sort None first | 2680 # 0 to sort to sort None first |
| 2680 # 1 is used to sort the integer values. | 2681 # 1 is used to sort the integer values. |
| 2681 NoneCode = (2,0)[NoneFirst] | 2682 NoneCode = (2, 0)[NoneFirst] |
| 2682 | 2683 |
| 2683 value = list(self.__iter__()) | 2684 value = list(self.__iter__()) |
| 2684 | 2685 |
| 2685 if not value: | 2686 if not value: |
| 2686 # return empty list, nothing to sort. | 2687 # return empty list, nothing to sort. |
| 2907 (hyperdb.Multilink, MultilinkHTMLProperty), | 2908 (hyperdb.Multilink, MultilinkHTMLProperty), |
| 2908 ] | 2909 ] |
| 2909 | 2910 |
| 2910 | 2911 |
| 2911 def register_propclass(prop, cls): | 2912 def register_propclass(prop, cls): |
| 2912 for index,propclass in enumerate(propclasses): | 2913 for index, propclass in enumerate(propclasses): |
| 2913 p, c = propclass | 2914 p, c = propclass |
| 2914 if prop == p: | 2915 if prop == p: |
| 2915 propclasses[index] = (prop, cls) | 2916 propclasses[index] = (prop, cls) |
| 2916 break | 2917 break |
| 2917 else: | 2918 else: |
| 3188 def __str__(self): | 3189 def __str__(self): |
| 3189 d = {} | 3190 d = {} |
| 3190 d.update(self.__dict__) | 3191 d.update(self.__dict__) |
| 3191 f = '' | 3192 f = '' |
| 3192 for k in self.form.keys(): | 3193 for k in self.form.keys(): |
| 3193 f += '\n %r=%r'%(k,handleListCGIValue(self.form[k])) | 3194 f += '\n %r=%r'%(k, handleListCGIValue(self.form[k])) |
| 3194 d['form'] = f | 3195 d['form'] = f |
| 3195 e = '' | 3196 e = '' |
| 3196 for k,v in self.env.items(): | 3197 for k, v in self.env.items(): |
| 3197 e += '\n %r=%r'%(k, v) | 3198 e += '\n %r=%r'%(k, v) |
| 3198 d['env'] = e | 3199 d['env'] = e |
| 3199 return """ | 3200 return """ |
| 3200 form: %(form)s | 3201 form: %(form)s |
| 3201 base: %(base)r | 3202 base: %(base)r |
| 3246 add(sc+'group', ','.join(val)) | 3247 add(sc+'group', ','.join(val)) |
| 3247 if filter and self.filter: | 3248 if filter and self.filter: |
| 3248 add(sc+'filter', ','.join(self.filter)) | 3249 add(sc+'filter', ','.join(self.filter)) |
| 3249 if self.classname and filterspec: | 3250 if self.classname and filterspec: |
| 3250 cls = self.client.db.getclass(self.classname) | 3251 cls = self.client.db.getclass(self.classname) |
| 3251 for k,v in self.filterspec.items(): | 3252 for k, v in self.filterspec.items(): |
| 3252 if k in exclude: | 3253 if k in exclude: |
| 3253 continue | 3254 continue |
| 3254 if isinstance(v, list): | 3255 if isinstance(v, list): |
| 3255 # id's are stored as strings but should be treated | 3256 # id's are stored as strings but should be treated |
| 3256 # as integers in lists. | 3257 # as integers in lists. |
| 3280 dispname otherwise the parameter will be omitted | 3281 dispname otherwise the parameter will be omitted |
| 3281 from the url. | 3282 from the url. |
| 3282 """ | 3283 """ |
| 3283 q = urllib_.quote | 3284 q = urllib_.quote |
| 3284 sc = self.special_char | 3285 sc = self.special_char |
| 3285 l = ['%s=%s'%(k,is_us(v) and q(v) or v) | 3286 l = ['%s=%s'%(k, is_us(v) and q(v) or v) |
| 3286 for k,v in args.items() if v is not None] | 3287 for k, v in args.items() if v is not None] |
| 3287 # pull out the special values (prefixed by @ or :) | 3288 # pull out the special values (prefixed by @ or :) |
| 3288 specials = {} | 3289 specials = {} |
| 3289 for key in args.keys(): | 3290 for key in args.keys(): |
| 3290 if key[0] in '@:': | 3291 if key[0] in '@:': |
| 3291 specials[key[1:]] = args[key] | 3292 specials[key[1:]] = args[key] |
| 3319 l.append(sc+'startwith=%s'%self.startwith) | 3320 l.append(sc+'startwith=%s'%self.startwith) |
| 3320 | 3321 |
| 3321 # finally, the remainder of the filter args in the request | 3322 # finally, the remainder of the filter args in the request |
| 3322 if self.classname and self.filterspec: | 3323 if self.classname and self.filterspec: |
| 3323 cls = self.client.db.getclass(self.classname) | 3324 cls = self.client.db.getclass(self.classname) |
| 3324 for k,v in self.filterspec.items(): | 3325 for k, v in self.filterspec.items(): |
| 3325 if k not in args: | 3326 if k not in args: |
| 3326 if isinstance(v, list): | 3327 if isinstance(v, list): |
| 3327 prop = cls.get_transitive_prop(k) | 3328 prop = cls.get_transitive_prop(k) |
| 3328 if k != 'id' and isinstance(prop, hyperdb.String): | 3329 if k != 'id' and isinstance(prop, hyperdb.String): |
| 3329 l.append('%s=%s'%(k, '%20'.join([q(i) for i in v]))) | 3330 l.append('%s=%s'%(k, '%20'.join([q(i) for i in v]))) |
| 3350 function help_window(helpurl, width, height) { | 3351 function help_window(helpurl, width, height) { |
| 3351 HelpWin = window.open('%s' + helpurl, 'RoundupHelpWindow', 'scrollbars=yes,resizable=yes,toolbar=no,height='+height+',width='+width); | 3352 HelpWin = window.open('%s' + helpurl, 'RoundupHelpWindow', 'scrollbars=yes,resizable=yes,toolbar=no,height='+height+',width='+width); |
| 3352 HelpWin.focus () | 3353 HelpWin.focus () |
| 3353 } | 3354 } |
| 3354 </script> | 3355 </script> |
| 3355 """%(self._client.client_nonce,self.base) | 3356 """%(self._client.client_nonce, self.base) |
| 3356 | 3357 |
| 3357 def batch(self, permission='View'): | 3358 def batch(self, permission='View'): |
| 3358 """ Return a batch object for results from the "current search" | 3359 """ Return a batch object for results from the "current search" |
| 3359 """ | 3360 """ |
| 3360 check = self._client.db.security.hasPermission | 3361 check = self._client.db.security.hasPermission |
