[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('''
<table width="300px" height="240px" align="center">
<tr valign="middle">
<td align="center">:_('front_page_text')</td>
<td align="center">::_('front_page_text')</td>
</tr>
</table>
''', template=AbstractWrapper.pxTemplate, hook='content')

View file

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

View file

@ -138,14 +138,20 @@ class Buffer:
def getLength(self): pass # To be overridden
def dumpStartElement(self, elem, attrs={}, ignoreAttrs=(),
insertAttributesHook=False, noEndTag=False):
def dumpStartElement(self, elem, attrs={}, ignoreAttrs=(), hook=False,
noEndTag=False):
'''Inserts into this buffer the start tag p_elem, with its p_attrs,
excepted those listed in p_ignoreAttrs. If p_insertAttributesHook
is True (works only for MemoryBuffers), we will insert an Attributes
instance at the end of the list of dumped attributes, in order to be
able, when evaluating the buffer, to dump additional attributes, not
known at this dump time.'''
excepted those listed in p_ignoreAttrs. If p_hook is not None
(works only for MemoryBuffers), we will insert, at the end of the
list of dumped attributes:
* [pod] an Attributes instance, in order to be able, when evaluating
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)
for name, value in attrs.items():
if ignoreAttrs and (name in ignoreAttrs): continue
@ -157,16 +163,14 @@ class Buffer:
self.write(' %s="' % name)
self.addExpression(value[1:])
self.write('"')
if insertAttributesHook:
res = self.addAttributes()
else:
res = None
res = None
if hook:
if self.pod:
res = self.addAttributes()
else:
self.addAttribute(*hook)
# Close the tag
if noEndTag:
suffix = '/>'
else:
suffix = '>'
self.write(suffix)
self.write(noEndTag and '/>' or '>')
return res
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.
try:
expr = Expression(expression, self.pod)
if tiedHook: tiedHook.tiedExpression = expr
res, escape = expr.evaluate(self.env.context)
if escape: self.dumpContent(res)
else: self.write(res)
@ -366,12 +371,19 @@ class MemoryBuffer(Buffer):
self.content += u' '
def addAttributes(self):
# Create the Attributes instance
'''pod-only: adds an Attributes instance into this buffer.'''
attrs = Attributes(self.env)
self.elements[self.getLength()] = attrs
self.content += u' '
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):
'''Returns variable definitions in p_expr as a list
~[(s_varName, s_expr)]~.'''
@ -656,7 +668,8 @@ class MemoryBuffer(Buffer):
evalEntry.expr, e), dumpTb=False)
else: # px
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))
else: # It is a subBuffer
if evalEntry.action:

View file

@ -185,4 +185,20 @@ class Attributes(PodElement):
for name, value in self.attrs.iteritems():
res += ' %s=%s' % (name, quoteattr(value))
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,
ignoreAttrs=(e.tags['formula'], e.tags['string-value'],
e.tags['value-type']),
insertAttributesHook=True)
hook=True)
# We already have the POD expression: remember it on the env.
e.currentOdsExpression = attrs[e.tags['string-value']]
e.currentOdsHook = hook

View file

@ -47,6 +47,7 @@ class PxParser(XmlParser):
pxAttributes = ('var', 'for', 'if')
# No-end tags
noEndTags = ('br', 'img', 'link', 'input')
noDumpTags = ('selected', 'checked')
def __init__(self, env, caller=None):
XmlParser.__init__(self, env, caller)
@ -73,8 +74,19 @@ class PxParser(XmlParser):
# the main element or to a sub-element.
e.currentBuffer.addElement(elem, elemType='px')
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,
ignoreAttrs=self.pxAttributes, noEndTag=elem in self.noEndTags)
ignoreAttrs=ignorableAttrs, noEndTag=elem in self.noEndTags,
hook=hook)
def endElement(self, elem):
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'
XML_SPECIAL_CHARS = {'<': '&lt;', '>': '&gt;', '&': '&amp;', '"': '&quot;',
"'": '&apos;'}
XML_ENTITIES = {'lt': '<', 'gt': '>', 'amp': '&', 'quot': "'", 'apos': "'"}
XML_ENTITIES = {'lt': '<', 'gt': '>', 'amp': '&', 'quot': '"', 'apos': "'"}
HTML_ENTITIES = {
'iexcl': '¡', 'cent': '¢', 'pound': '£', 'curren': '', 'yen': '¥',
'brvbar': 'Š', 'sect': '§', 'uml': '¨', 'copy':'©', 'ordf':'ª',