Mercurial > p > roundup > code
comparison roundup/cgi/templating.py @ 4267:c5f52c2c9e36
Provide ability to specify arbitrary HTML attributes.
| author | Stefan Seefeld <stefan@seefeld.name> |
|---|---|
| date | Fri, 09 Oct 2009 13:58:43 +0000 |
| parents | 01ef28bffcbd |
| children | b78eb8fc821a |
comparison
equal
deleted
inserted
replaced
| 4266:2b75274936bc | 4267:c5f52c2c9e36 |
|---|---|
| 418 else: | 418 else: |
| 419 dic['id'] = dic['name'] | 419 dic['id'] = dic['name'] |
| 420 except KeyError: | 420 except KeyError: |
| 421 pass | 421 pass |
| 422 | 422 |
| 423 def cgi_escape_attrs(**attrs): | |
| 424 return ' '.join(['%s="%s"'%(k,cgi.escape(str(v), True)) | |
| 425 for k,v in attrs.items()]) | |
| 426 | |
| 423 def input_html4(**attrs): | 427 def input_html4(**attrs): |
| 424 """Generate an 'input' (html4) element with given attributes""" | 428 """Generate an 'input' (html4) element with given attributes""" |
| 425 _set_input_default_args(attrs) | 429 _set_input_default_args(attrs) |
| 426 return '<input %s>'%' '.join(['%s="%s"'%(k,cgi.escape(str(v), True)) | 430 return '<input %s>'%cgi_escape_attrs(**attrs) |
| 427 for k,v in attrs.items()]) | |
| 428 | 431 |
| 429 def input_xhtml(**attrs): | 432 def input_xhtml(**attrs): |
| 430 """Generate an 'input' (xhtml) element with given attributes""" | 433 """Generate an 'input' (xhtml) element with given attributes""" |
| 431 _set_input_default_args(attrs) | 434 _set_input_default_args(attrs) |
| 432 return '<input %s/>'%' '.join(['%s="%s"'%(k,cgi.escape(str(v), True)) | 435 return '<input %s/>'%cgi_escape_attrs(**attrs) |
| 433 for k,v in attrs.items()]) | |
| 434 | 436 |
| 435 class HTMLInputMixin: | 437 class HTMLInputMixin: |
| 436 """ requires a _client property """ | 438 """ requires a _client property """ |
| 437 def __init__(self): | 439 def __init__(self): |
| 438 html_version = 'html4' | 440 html_version = 'html4' |
| 1462 else: | 1464 else: |
| 1463 value = cgi.escape(str(self._value)) | 1465 value = cgi.escape(str(self._value)) |
| 1464 | 1466 |
| 1465 value = '"'.join(value.split('"')) | 1467 value = '"'.join(value.split('"')) |
| 1466 name = self._formname | 1468 name = self._formname |
| 1467 passthrough_args = ' '.join(['%s="%s"' % (k, cgi.escape(str(v), True)) | 1469 passthrough_args = cgi_escape_attrs(**kwargs) |
| 1468 for k,v in kwargs.items()]) | |
| 1469 return ('<textarea %(passthrough_args)s name="%(name)s" id="%(name)s"' | 1470 return ('<textarea %(passthrough_args)s name="%(name)s" id="%(name)s"' |
| 1470 ' rows="%(rows)s" cols="%(cols)s">' | 1471 ' rows="%(rows)s" cols="%(cols)s">' |
| 1471 '%(value)s</textarea>') % locals() | 1472 '%(value)s</textarea>') % locals() |
| 1472 | 1473 |
| 1473 def email(self, escape=1): | 1474 def email(self, escape=1): |
| 1501 | 1502 |
| 1502 if self._value is None: | 1503 if self._value is None: |
| 1503 return '' | 1504 return '' |
| 1504 return self._('*encrypted*') | 1505 return self._('*encrypted*') |
| 1505 | 1506 |
| 1506 def field(self, size=30): | 1507 def field(self, size=30, **kwargs): |
| 1507 """ Render a form edit field for the property. | 1508 """ Render a form edit field for the property. |
| 1508 | 1509 |
| 1509 If not editable, just display the value via plain(). | 1510 If not editable, just display the value via plain(). |
| 1510 """ | 1511 """ |
| 1511 if not self.is_edit_ok(): | 1512 if not self.is_edit_ok(): |
| 1512 return self.plain(escape=1) | 1513 return self.plain(escape=1) |
| 1513 | 1514 |
| 1514 return self.input(type="password", name=self._formname, size=size) | 1515 return self.input(type="password", name=self._formname, size=size, |
| 1516 **kwargs) | |
| 1515 | 1517 |
| 1516 def confirm(self, size=30): | 1518 def confirm(self, size=30): |
| 1517 """ Render a second form edit field for the property, used for | 1519 """ Render a second form edit field for the property, used for |
| 1518 confirmation that the user typed the password correctly. Generates | 1520 confirmation that the user typed the password correctly. Generates |
| 1519 a field with name "@confirm@name". | 1521 a field with name "@confirm@name". |
| 1538 if self._value is None: | 1540 if self._value is None: |
| 1539 return '' | 1541 return '' |
| 1540 | 1542 |
| 1541 return str(self._value) | 1543 return str(self._value) |
| 1542 | 1544 |
| 1543 def field(self, size=30): | 1545 def field(self, size=30, **kwargs): |
| 1544 """ Render a form edit field for the property. | 1546 """ Render a form edit field for the property. |
| 1545 | 1547 |
| 1546 If not editable, just display the value via plain(). | 1548 If not editable, just display the value via plain(). |
| 1547 """ | 1549 """ |
| 1548 if not self.is_edit_ok(): | 1550 if not self.is_edit_ok(): |
| 1550 | 1552 |
| 1551 value = self._value | 1553 value = self._value |
| 1552 if value is None: | 1554 if value is None: |
| 1553 value = '' | 1555 value = '' |
| 1554 | 1556 |
| 1555 return self.input(name=self._formname, value=value, size=size) | 1557 return self.input(name=self._formname, value=value, size=size, |
| 1558 **kwargs) | |
| 1556 | 1559 |
| 1557 def __int__(self): | 1560 def __int__(self): |
| 1558 """ Return an int of me | 1561 """ Return an int of me |
| 1559 """ | 1562 """ |
| 1560 return int(self._value) | 1563 return int(self._value) |
| 1574 | 1577 |
| 1575 if self._value is None: | 1578 if self._value is None: |
| 1576 return '' | 1579 return '' |
| 1577 return self._value and self._("Yes") or self._("No") | 1580 return self._value and self._("Yes") or self._("No") |
| 1578 | 1581 |
| 1579 def field(self): | 1582 def field(self, **kwargs): |
| 1580 """ Render a form edit field for the property | 1583 """ Render a form edit field for the property |
| 1581 | 1584 |
| 1582 If not editable, just display the value via plain(). | 1585 If not editable, just display the value via plain(). |
| 1583 """ | 1586 """ |
| 1584 if not self.is_edit_ok(): | 1587 if not self.is_edit_ok(): |
| 1590 'on', '1') | 1593 'on', '1') |
| 1591 | 1594 |
| 1592 checked = value and "checked" or "" | 1595 checked = value and "checked" or "" |
| 1593 if value: | 1596 if value: |
| 1594 s = self.input(type="radio", name=self._formname, value="yes", | 1597 s = self.input(type="radio", name=self._formname, value="yes", |
| 1595 checked="checked") | 1598 checked="checked", **kwargs) |
| 1596 s += self._('Yes') | 1599 s += self._('Yes') |
| 1597 s +=self.input(type="radio", name=self._formname, value="no") | 1600 s +=self.input(type="radio", name=self._formname, value="no", |
| 1601 **kwargs) | |
| 1598 s += self._('No') | 1602 s += self._('No') |
| 1599 else: | 1603 else: |
| 1600 s = self.input(type="radio", name=self._formname, value="yes") | 1604 s = self.input(type="radio", name=self._formname, value="yes", |
| 1605 **kwargs) | |
| 1601 s += self._('Yes') | 1606 s += self._('Yes') |
| 1602 s +=self.input(type="radio", name=self._formname, value="no", | 1607 s +=self.input(type="radio", name=self._formname, value="no", |
| 1603 checked="checked") | 1608 checked="checked", **kwargs) |
| 1604 s += self._('No') | 1609 s += self._('No') |
| 1605 return s | 1610 return s |
| 1606 | 1611 |
| 1607 class DateHTMLProperty(HTMLProperty): | 1612 class DateHTMLProperty(HTMLProperty): |
| 1608 | 1613 |
| 1656 ret = ret - interval | 1661 ret = ret - interval |
| 1657 | 1662 |
| 1658 return DateHTMLProperty(self._client, self._classname, self._nodeid, | 1663 return DateHTMLProperty(self._client, self._classname, self._nodeid, |
| 1659 self._prop, self._formname, ret) | 1664 self._prop, self._formname, ret) |
| 1660 | 1665 |
| 1661 def field(self, size=30, default=None, format=_marker, popcal=True): | 1666 def field(self, size=30, default=None, format=_marker, popcal=True, |
| 1667 **kwargs): | |
| 1662 """Render a form edit field for the property | 1668 """Render a form edit field for the property |
| 1663 | 1669 |
| 1664 If not editable, just display the value via plain(). | 1670 If not editable, just display the value via plain(). |
| 1665 | 1671 |
| 1666 If "popcal" then include the Javascript calendar editor. | 1672 If "popcal" then include the Javascript calendar editor. |
| 1691 'DateHTMLProperty must be either DateHTMLProperty ' | 1697 'DateHTMLProperty must be either DateHTMLProperty ' |
| 1692 'or string date representation.') | 1698 'or string date representation.') |
| 1693 elif isinstance(value, str) or isinstance(value, unicode): | 1699 elif isinstance(value, str) or isinstance(value, unicode): |
| 1694 # most likely erroneous input to be passed back to user | 1700 # most likely erroneous input to be passed back to user |
| 1695 if isinstance(value, unicode): value = value.encode('utf8') | 1701 if isinstance(value, unicode): value = value.encode('utf8') |
| 1696 return self.input(name=self._formname, value=value, size=size) | 1702 return self.input(name=self._formname, value=value, size=size, |
| 1703 **kwargs) | |
| 1697 else: | 1704 else: |
| 1698 raw_value = value | 1705 raw_value = value |
| 1699 | 1706 |
| 1700 if raw_value is None: | 1707 if raw_value is None: |
| 1701 value = '' | 1708 value = '' |
| 1711 offset = self._offset | 1718 offset = self._offset |
| 1712 value = raw_value.local(offset) | 1719 value = raw_value.local(offset) |
| 1713 if format is not self._marker: | 1720 if format is not self._marker: |
| 1714 value = value.pretty(format) | 1721 value = value.pretty(format) |
| 1715 | 1722 |
| 1716 s = self.input(name=self._formname, value=value, size=size) | 1723 s = self.input(name=self._formname, value=value, size=size, |
| 1724 **kwargs) | |
| 1717 if popcal: | 1725 if popcal: |
| 1718 s += self.popcal() | 1726 s += self.popcal() |
| 1719 return s | 1727 return s |
| 1720 | 1728 |
| 1721 def reldate(self, pretty=1): | 1729 def reldate(self, pretty=1): |
| 1806 if not self.is_view_ok(): | 1814 if not self.is_view_ok(): |
| 1807 return self._('[hidden]') | 1815 return self._('[hidden]') |
| 1808 | 1816 |
| 1809 return self._value.pretty() | 1817 return self._value.pretty() |
| 1810 | 1818 |
| 1811 def field(self, size=30): | 1819 def field(self, size=30, **kwargs): |
| 1812 """ Render a form edit field for the property | 1820 """ Render a form edit field for the property |
| 1813 | 1821 |
| 1814 If not editable, just display the value via plain(). | 1822 If not editable, just display the value via plain(). |
| 1815 """ | 1823 """ |
| 1816 if not self.is_edit_ok(): | 1824 if not self.is_edit_ok(): |
| 1818 | 1826 |
| 1819 value = self._value | 1827 value = self._value |
| 1820 if value is None: | 1828 if value is None: |
| 1821 value = '' | 1829 value = '' |
| 1822 | 1830 |
| 1823 return self.input(name=self._formname, value=value, size=size) | 1831 return self.input(name=self._formname, value=value, size=size, |
| 1832 **kwargs) | |
| 1824 | 1833 |
| 1825 class LinkHTMLProperty(HTMLProperty): | 1834 class LinkHTMLProperty(HTMLProperty): |
| 1826 """ Link HTMLProperty | 1835 """ Link HTMLProperty |
| 1827 Include the above as well as being able to access the class | 1836 Include the above as well as being able to access the class |
| 1828 information. Stringifying the object itself results in the value | 1837 information. Stringifying the object itself results in the value |
| 1871 value = self._value | 1880 value = self._value |
| 1872 if escape: | 1881 if escape: |
| 1873 value = cgi.escape(value) | 1882 value = cgi.escape(value) |
| 1874 return value | 1883 return value |
| 1875 | 1884 |
| 1876 def field(self, showid=0, size=None): | 1885 def field(self, showid=0, size=None, **kwargs): |
| 1877 """ Render a form edit field for the property | 1886 """ Render a form edit field for the property |
| 1878 | 1887 |
| 1879 If not editable, just display the value via plain(). | 1888 If not editable, just display the value via plain(). |
| 1880 """ | 1889 """ |
| 1881 if not self.is_edit_ok(): | 1890 if not self.is_edit_ok(): |
| 1889 k = linkcl.getkey() | 1898 k = linkcl.getkey() |
| 1890 if k and num_re.match(self._value): | 1899 if k and num_re.match(self._value): |
| 1891 value = linkcl.get(self._value, k) | 1900 value = linkcl.get(self._value, k) |
| 1892 else: | 1901 else: |
| 1893 value = self._value | 1902 value = self._value |
| 1894 return self.input(name=self._formname, value=value, size=size) | 1903 return self.input(name=self._formname, value=value, size=size, |
| 1904 **kwargs) | |
| 1895 | 1905 |
| 1896 def menu(self, size=None, height=None, showid=0, additional=[], value=None, | 1906 def menu(self, size=None, height=None, showid=0, additional=[], value=None, |
| 1897 sort_on=None, **conditions): | 1907 sort_on=None, html_kwargs = {}, **conditions): |
| 1898 """ Render a form select list for this property | 1908 """ Render a form select list for this property |
| 1899 | 1909 |
| 1900 "size" is used to limit the length of the list labels | 1910 "size" is used to limit the length of the list labels |
| 1901 "height" is used to set the <select> tag's "size" attribute | 1911 "height" is used to set the <select> tag's "size" attribute |
| 1902 "showid" includes the item ids in the list labels | 1912 "showid" includes the item ids in the list labels |
| 1925 value = self._value | 1935 value = self._value |
| 1926 elif value == '-1': | 1936 elif value == '-1': |
| 1927 value = None | 1937 value = None |
| 1928 | 1938 |
| 1929 linkcl = self._db.getclass(self._prop.classname) | 1939 linkcl = self._db.getclass(self._prop.classname) |
| 1930 l = ['<select name="%s">'%self._formname] | 1940 l = ['<select %s>'%cgi_escape_attrs(name = self._formname, |
| 1941 **html_kwargs)] | |
| 1931 k = linkcl.labelprop(1) | 1942 k = linkcl.labelprop(1) |
| 1932 s = '' | 1943 s = '' |
| 1933 if value is None: | 1944 if value is None: |
| 1934 s = 'selected="selected" ' | 1945 s = 'selected="selected" ' |
| 1935 l.append(self._('<option %svalue="-1">- no selection -</option>')%s) | 1946 l.append(self._('<option %svalue="-1">- no selection -</option>')%s) |
| 2091 value = ', '.join(labels) | 2102 value = ', '.join(labels) |
| 2092 if escape: | 2103 if escape: |
| 2093 value = cgi.escape(value) | 2104 value = cgi.escape(value) |
| 2094 return value | 2105 return value |
| 2095 | 2106 |
| 2096 def field(self, size=30, showid=0): | 2107 def field(self, size=30, showid=0, **kwargs): |
| 2097 """ Render a form edit field for the property | 2108 """ Render a form edit field for the property |
| 2098 | 2109 |
| 2099 If not editable, just display the value via plain(). | 2110 If not editable, just display the value via plain(). |
| 2100 """ | 2111 """ |
| 2101 if not self.is_edit_ok(): | 2112 if not self.is_edit_ok(): |
| 2108 showid=1 | 2119 showid=1 |
| 2109 if not showid: | 2120 if not showid: |
| 2110 k = linkcl.labelprop(1) | 2121 k = linkcl.labelprop(1) |
| 2111 value = lookupKeys(linkcl, k, value) | 2122 value = lookupKeys(linkcl, k, value) |
| 2112 value = ','.join(value) | 2123 value = ','.join(value) |
| 2113 return self.input(name=self._formname, size=size, value=value) | 2124 return self.input(name=self._formname, size=size, value=value, |
| 2125 **kwargs) | |
| 2114 | 2126 |
| 2115 def menu(self, size=None, height=None, showid=0, additional=[], | 2127 def menu(self, size=None, height=None, showid=0, additional=[], |
| 2116 value=None, sort_on=None, **conditions): | 2128 value=None, sort_on=None, html_kwargs = {}, **conditions): |
| 2117 """ Render a form <select> list for this property. | 2129 """ Render a form <select> list for this property. |
| 2118 | 2130 |
| 2119 "size" is used to limit the length of the list labels | 2131 "size" is used to limit the length of the list labels |
| 2120 "height" is used to set the <select> tag's "size" attribute | 2132 "height" is used to set the <select> tag's "size" attribute |
| 2121 "showid" includes the item ids in the list labels | 2133 "showid" includes the item ids in the list labels |
| 2164 height = len(options) | 2176 height = len(options) |
| 2165 if value: | 2177 if value: |
| 2166 # The "no selection" option. | 2178 # The "no selection" option. |
| 2167 height += 1 | 2179 height += 1 |
| 2168 height = min(height, 7) | 2180 height = min(height, 7) |
| 2169 l = ['<select multiple name="%s" size="%s">'%(self._formname, height)] | 2181 l = ['<select multiple %s>'%cgi_escape_attrs(name = self._formname, |
| 2182 size = height, | |
| 2183 **html_kwargs)] | |
| 2170 k = linkcl.labelprop(1) | 2184 k = linkcl.labelprop(1) |
| 2171 | 2185 |
| 2172 if value: | 2186 if value: |
| 2173 l.append('<option value="%s">- no selection -</option>' | 2187 l.append('<option value="%s">- no selection -</option>' |
| 2174 % ','.join(['-' + v for v in value])) | 2188 % ','.join(['-' + v for v in value])) |
