[px] Managed special HTML attributes like 'checked' and 'selected'.

This commit is contained in:
Gaetan Delannay 2013-06-26 13:44:31 +02:00
parent 5ece5c9831
commit e4b84be05e
7 changed files with 103 additions and 63 deletions

View file

@ -24,7 +24,7 @@ class ToolWrapper(AbstractWrapper):
pxHome = Px(''' pxHome = Px('''
<table width="300px" height="240px" align="center"> <table width="300px" height="240px" align="center">
<tr valign="middle"> <tr valign="middle">
<td align="center">:_('front_page_text')</td> <td align="center">::_('front_page_text')</td>
</tr> </tr>
</table> </table>
''', template=AbstractWrapper.pxTemplate, hook='content') ''', template=AbstractWrapper.pxTemplate, hook='content')

View file

@ -77,9 +77,9 @@ class AbstractWrapper(object):
<br/> <br/>
</div> </div>
<br/> <br/>
<input type="button" onclick="doConfirm()" value="_('yes')"/> <input type="button" onclick="doConfirm()" value=":_('yes')"/>
<input type="button" onclick="closePopup('confirmActionPopup')" <input type="button" onclick="closePopup('confirmActionPopup')"
value="_('no')"/> value=":_('no')"/>
</div> </div>
</form> </form>
</div> </div>
@ -101,44 +101,44 @@ class AbstractWrapper(object):
</form> </form>
</div> </div>
<!--
<table class="main" align="center" cellpadding="0"> <table class="main" align="center" cellpadding="0">
<tal:comment replace="nothing">Top banner</tal:comment> <tr class="top">
<tr class="top" metal:define-slot="top"> <!-- Top banner -->
<td tal:define="bannerName python: (dir == 'ltr') and 'banner' or 'bannerrtl'" <td var="bannerName=(dir == 'ltr') and 'banner' or 'bannerrtl'"
tal:attributes="style python: 'background-image: url(%s/ui/%s.jpg)' % (appUrl, bannerName)"> style=":'background-image: url(%s/ui/%s.jpg)'% (appUrl,bannerName)">
<tal:comment replace="nothing">Top links</tal:comment>
<div style="margin-top: 4px" <!-- Top links -->
tal:define="pages tool/getMainPages" tal:attributes="align dright"> <div style="margin-top: 4px" align=":dright">
<tal:comment replace="nothing">Icon "home"</tal:comment> <!-- Icon "home" -->
<a class="pageLink" tal:attributes="href appUrl; title python: _('app_home')"> <a class="pageLink" href=":appUrl" title=": _('app_home')">
<img tal:attributes="src string: $appUrl/ui/home.gif" style="margin-right: 3px"/> <img src=":'%s/ui/home.gif' % appUrl" style="margin-right: 3px"/>
</a> </a>
<tal:comment replace="nothing">Additional links (or icons) from icons.pt</tal:comment> <!-- Additional links (or icons) from icons.pt -->
<metal:call use-macro="app/ui/icons/macros/links"/> <!--metal:call use-macro="app/ui/icons/macros/links"/-->
<tal:comment replace="nothing">Top-level pages</tal:comment>
<a tal:repeat="page pages" class="pageLink" <!-- Top-level pages -->
tal:content="page/title" tal:attributes="href page/absolute_url"></a> <a for="page in tool.pages" class="pageLink"
<tal:comment replace="nothing">Connect link if discreet login</tal:comment> href=":page.url">:page.title</a>
<a id="loginLink" name="loginLink" onclick="showLoginForm()" class="pageLink" style="cursor:pointer"
tal:condition="python: isAnon and discreetLogin" tal:content="python: _('app_connect')"> <!-- Connect link if discreet login -->
</a> <a if="isAnon and discreetLogin" id="loginLink" name="loginLink"
<tal:comment replace="nothing">Language selector</tal:comment> onclick="showLoginForm()" class="pageLink"
<tal:lg condition="tool/showLanguageSelector"> style="cursor:pointer">:_('app_connect')</a>
<!-- Language selector -->
<x if="ztool.showLanguageSelector()">
<select class="pageLink" <select class="pageLink"
tal:define="languages tool/getLanguages; var="languages=ztool.getLanguages();
defaultLanguage python: languages[0]" defaultLanguage=languages[0]"
tal:attributes="onchange string:window.location='$appUrl/config/changeLanguage?language=' + this.options[this.selectedIndex].value"> onchange=":'window.location=&quot;%s/config/changeLanguage?language=&quot; + this.options[this.selectedIndex].value' % appUrl">
<option tal:repeat="lg languages" <option for="lg in languages" value=":lg"
tal:content="python: tool.getLanguageName(lg)" selected=":lang == lg">:ztool.getLanguageName(lg)</option>
tal:attributes="selected python:lang == lg; value lg">
</option>
</select> </select>
</tal:lg> </x>
</div> </div>
</td> </td>
</tr> </tr>
<tal:comment replace="nothing">The message strip</tal:comment> <!--tal:comment replace="nothing">The message strip</tal:comment>
<tr valign="top"> <tr valign="top">
<td> <td>
<div style="position: relative"> <div style="position: relative">
@ -230,9 +230,8 @@ class AbstractWrapper(object):
</tr> </tr>
<tr><tal:comment replace="nothing">Footer</tal:comment> <tr><tal:comment replace="nothing">Footer</tal:comment>
<td><metal:call use-macro="app/ui/footer/macros/footer"/></td> <td><metal:call use-macro="app/ui/footer/macros/footer"/></td>
</tr> </tr-->
</table> </table>
-->
<x>:content</x> <x>:content</x>
</body> </body>
</html> </html>

View file

@ -138,14 +138,20 @@ class Buffer:
def getLength(self): pass # To be overridden def getLength(self): pass # To be overridden
def dumpStartElement(self, elem, attrs={}, ignoreAttrs=(), def dumpStartElement(self, elem, attrs={}, ignoreAttrs=(), hook=False,
insertAttributesHook=False, noEndTag=False): noEndTag=False):
'''Inserts into this buffer the start tag p_elem, with its p_attrs, '''Inserts into this buffer the start tag p_elem, with its p_attrs,
excepted those listed in p_ignoreAttrs. If p_insertAttributesHook excepted those listed in p_ignoreAttrs. If p_hook is not None
is True (works only for MemoryBuffers), we will insert an Attributes (works only for MemoryBuffers), we will insert, at the end of the
instance at the end of the list of dumped attributes, in order to be list of dumped attributes:
able, when evaluating the buffer, to dump additional attributes, not * [pod] an Attributes instance, in order to be able, when evaluating
known at this dump time.''' the buffer, to dump additional attributes, not known at this
dump time;
* [px] an Attribute instance, representing a special HTML attribute
like "checked" or "selected", that, if the tied expression
returns False, must not be dumped at all. In this case,
p_hook must be a tuple (s_attrName, s_expr).
'''
self.write('<%s' % elem) self.write('<%s' % elem)
for name, value in attrs.items(): for name, value in attrs.items():
if ignoreAttrs and (name in ignoreAttrs): continue if ignoreAttrs and (name in ignoreAttrs): continue
@ -157,16 +163,14 @@ class Buffer:
self.write(' %s="' % name) self.write(' %s="' % name)
self.addExpression(value[1:]) self.addExpression(value[1:])
self.write('"') self.write('"')
if insertAttributesHook: res = None
if hook:
if self.pod:
res = self.addAttributes() res = self.addAttributes()
else: else:
res = None self.addAttribute(*hook)
# Close the tag # Close the tag
if noEndTag: self.write(noEndTag and '/>' or '>')
suffix = '/>'
else:
suffix = '>'
self.write(suffix)
return res return res
def dumpEndElement(self, elem): def dumpEndElement(self, elem):
@ -212,6 +216,7 @@ class FileBuffer(Buffer):
# At 2013-02-06, this method was not called within the whole test suite. # At 2013-02-06, this method was not called within the whole test suite.
try: try:
expr = Expression(expression, self.pod) expr = Expression(expression, self.pod)
if tiedHook: tiedHook.tiedExpression = expr
res, escape = expr.evaluate(self.env.context) res, escape = expr.evaluate(self.env.context)
if escape: self.dumpContent(res) if escape: self.dumpContent(res)
else: self.write(res) else: self.write(res)
@ -366,12 +371,19 @@ class MemoryBuffer(Buffer):
self.content += u' ' self.content += u' '
def addAttributes(self): def addAttributes(self):
# Create the Attributes instance '''pod-only: adds an Attributes instance into this buffer.'''
attrs = Attributes(self.env) attrs = Attributes(self.env)
self.elements[self.getLength()] = attrs self.elements[self.getLength()] = attrs
self.content += u' ' self.content += u' '
return attrs return attrs
def addAttribute(self, name, expr):
'''px-only: adds an Attribute instance into this buffer.'''
attr = Attribute(name, expr)
self.elements[self.getLength()] = attr
self.content += u' '
return attr
def _getVariables(self, expr): def _getVariables(self, expr):
'''Returns variable definitions in p_expr as a list '''Returns variable definitions in p_expr as a list
~[(s_varName, s_expr)]~.''' ~[(s_varName, s_expr)]~.'''
@ -656,7 +668,8 @@ class MemoryBuffer(Buffer):
evalEntry.expr, e), dumpTb=False) evalEntry.expr, e), dumpTb=False)
else: # px else: # px
raise Exception(EVAL_EXPR_ERROR %(evalEntry.expr,e)) raise Exception(EVAL_EXPR_ERROR %(evalEntry.expr,e))
elif isinstance(evalEntry, Attributes): elif isinstance(evalEntry, Attributes) or \
isinstance(evalEntry, Attribute):
result.write(evalEntry.evaluate(context)) result.write(evalEntry.evaluate(context))
else: # It is a subBuffer else: # It is a subBuffer
if evalEntry.action: if evalEntry.action:

View file

@ -185,4 +185,20 @@ class Attributes(PodElement):
for name, value in self.attrs.iteritems(): for name, value in self.attrs.iteritems():
res += ' %s=%s' % (name, quoteattr(value)) res += ' %s=%s' % (name, quoteattr(value))
return res return res
class Attribute(PodElement):
'''Represents an HTML special attribute like "selected" or "checked".
px-only.'''
OD = None
def __init__(self, name, expr):
# The name of the attribute
self.name = name
# The expression that will compute the attribute value
self.expr = expr.strip()
def evaluate(self, context):
# If the expr evaluates to False, we do not dump the attribute at all.
if eval(self.expr, context): return ' %s="%s"' % (self.name, self.name)
return ''
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View file

@ -259,7 +259,7 @@ class PodParser(OdfParser):
hook = e.currentBuffer.dumpStartElement(elem, attrs, hook = e.currentBuffer.dumpStartElement(elem, attrs,
ignoreAttrs=(e.tags['formula'], e.tags['string-value'], ignoreAttrs=(e.tags['formula'], e.tags['string-value'],
e.tags['value-type']), e.tags['value-type']),
insertAttributesHook=True) hook=True)
# We already have the POD expression: remember it on the env. # We already have the POD expression: remember it on the env.
e.currentOdsExpression = attrs[e.tags['string-value']] e.currentOdsExpression = attrs[e.tags['string-value']]
e.currentOdsHook = hook e.currentOdsHook = hook

View file

@ -47,6 +47,7 @@ class PxParser(XmlParser):
pxAttributes = ('var', 'for', 'if') pxAttributes = ('var', 'for', 'if')
# No-end tags # No-end tags
noEndTags = ('br', 'img', 'link', 'input') noEndTags = ('br', 'img', 'link', 'input')
noDumpTags = ('selected', 'checked')
def __init__(self, env, caller=None): def __init__(self, env, caller=None):
XmlParser.__init__(self, env, caller) XmlParser.__init__(self, env, caller)
@ -73,8 +74,19 @@ class PxParser(XmlParser):
# the main element or to a sub-element. # the main element or to a sub-element.
e.currentBuffer.addElement(elem, elemType='px') e.currentBuffer.addElement(elem, elemType='px')
if elem != 'x': if elem != 'x':
# Dump the start elements and its attributes. But as a preamble,
# manage special attributes that could not be dumped at all, like
# "selected" or "checked".
hook = None
ignorableAttrs = self.pxAttributes
for name in self.noDumpTags:
if attrs.has_key(name) and attrs[name].startswith(':'):
hook = (name, attrs[name][1:])
ignorableAttrs += (name,)
break
e.currentBuffer.dumpStartElement(elem, attrs, e.currentBuffer.dumpStartElement(elem, attrs,
ignoreAttrs=self.pxAttributes, noEndTag=elem in self.noEndTags) ignoreAttrs=ignorableAttrs, noEndTag=elem in self.noEndTags,
hook=hook)
def endElement(self, elem): def endElement(self, elem):
e = self.env e = self.env

View file

@ -37,7 +37,7 @@ CUSTOM_CONVERSION_ERROR = 'Custom converter for "%s" values produced an ' \
'error while converting value "%s". %s' 'error while converting value "%s". %s'
XML_SPECIAL_CHARS = {'<': '&lt;', '>': '&gt;', '&': '&amp;', '"': '&quot;', XML_SPECIAL_CHARS = {'<': '&lt;', '>': '&gt;', '&': '&amp;', '"': '&quot;',
"'": '&apos;'} "'": '&apos;'}
XML_ENTITIES = {'lt': '<', 'gt': '>', 'amp': '&', 'quot': "'", 'apos': "'"} XML_ENTITIES = {'lt': '<', 'gt': '>', 'amp': '&', 'quot': '"', 'apos': "'"}
HTML_ENTITIES = { HTML_ENTITIES = {
'iexcl': '¡', 'cent': '¢', 'pound': '£', 'curren': '', 'yen': '¥', 'iexcl': '¡', 'cent': '¢', 'pound': '£', 'curren': '', 'yen': '¥',
'brvbar': 'Š', 'sect': '§', 'uml': '¨', 'copy':'©', 'ordf':'ª', 'brvbar': 'Š', 'sect': '§', 'uml': '¨', 'copy':'©', 'ordf':'ª',