summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Jung <yet@gmx.de>2009-05-11 08:50:08 +0000
committerAndreas Jung <yet@gmx.de>2009-05-11 08:50:08 +0000
commiteac40552db16e2c67e1eb3e0de028601d32e7c1d (patch)
tree99c49994f577c62d23369800c0c93e5f02866999
parentc5fb331c37e1985f23205083346a9d5ebf2caf49 (diff)
downloadzope-tal-eac40552db16e2c67e1eb3e0de028601d32e7c1d.tar.gz
- Launchpad #3742721 - 'structure' directive support within
tal:attributes
-rw-r--r--CHANGES.txt6
-rw-r--r--src/zope/tal/taldefs.py6
-rw-r--r--src/zope/tal/talgenerator.py18
-rw-r--r--src/zope/tal/talinterpreter.py7
-rw-r--r--src/zope/tal/tests/test_htmltalparser.py12
-rw-r--r--src/zope/tal/tests/test_talinterpreter.py14
6 files changed, 41 insertions, 22 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index da2b6a4..6e9f59f 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -2,10 +2,12 @@
CHANGES
=======
-3.5.2 (unreleased)
+3.6.0 (unreleased)
------------------
-- ...
+- Launchpad #3742721 - 'structure' directive support within
+ tal:attributes
+
3.5.1 (2009-03-08)
diff --git a/src/zope/tal/taldefs.py b/src/zope/tal/taldefs.py
index 554a4fe..ffd7eb8 100644
--- a/src/zope/tal/taldefs.py
+++ b/src/zope/tal/taldefs.py
@@ -111,7 +111,7 @@ class ErrorInfo(object):
self.offset = position[1]
-_attr_re = re.compile(r"\s*([^\s]+)\s+([^\s].*)\Z", re.S)
+_attr_re = re.compile(r"\s*([^\s]+)\s+(?:(text|structure)\s+)?([^\s].*)\Z", re.S)
_subst_re = re.compile(r"\s*(?:(text|structure)\s+)?(.*)\Z", re.S)
def parseAttributeReplacements(arg, xml):
@@ -120,12 +120,12 @@ def parseAttributeReplacements(arg, xml):
m = _attr_re.match(part)
if not m:
raise TALError("Bad syntax in attributes: %r" % part)
- name, expr = m.groups()
+ name, rep_type, expr = m.groups()
if not xml:
name = name.lower()
if name in dict:
raise TALError("Duplicate attribute name in attributes: %r" % part)
- dict[name] = expr
+ dict[name] = expr, rep_type or 'text'
return dict
def parseSubstitution(arg, position=(None, None)):
diff --git a/src/zope/tal/talgenerator.py b/src/zope/tal/talgenerator.py
index e01bd50..fcff484 100644
--- a/src/zope/tal/talgenerator.py
+++ b/src/zope/tal/talgenerator.py
@@ -452,13 +452,13 @@ class TALGenerator(object):
for item in attrlist:
key = item[0]
if repldict.has_key(key):
- expr, xlat, msgid = repldict[key]
- item = item[:2] + ("replace", expr, xlat, msgid)
+ expr, repl_type, xlat, msgid = repldict[key]
+ item = item[:2] + ("replace", expr, repl_type, xlat, msgid)
del repldict[key]
newlist.append(item)
# Add dynamic-only attributes
- for key, (expr, xlat, msgid) in repldict.items():
- newlist.append((key, None, "insert", expr, xlat, msgid))
+ for key, (expr, repl_type, xlat, msgid) in repldict.items():
+ newlist.append((key, None, "insert", expr, repl_type, xlat, msgid))
return newlist
def emitStartElement(self, name, attrlist, taldict, metaldict, i18ndict,
@@ -681,19 +681,19 @@ class TALGenerator(object):
self.xml)
else:
i18nattrs = {}
- # Convert repldict's name-->expr mapping to a
- # name-->(compiled_expr, translate) mapping
- for key, value in repldict.items():
+ # Convert repldict's name-->(expr, repl_type) mapping to a
+ # name-->(compiled_expr, repl_type, translate) mapping
+ for key, (value, repl_type) in repldict.items():
if i18nattrs.get(key, None):
raise I18NError(
"attribute [%s] cannot both be part of tal:attributes"
" and have a msgid in i18n:attributes" % key,
position)
ce = self.compileExpression(value)
- repldict[key] = ce, key in i18nattrs, i18nattrs.get(key)
+ repldict[key] = ce, repl_type, key in i18nattrs, i18nattrs.get(key)
for key in i18nattrs:
if key not in repldict:
- repldict[key] = None, 1, i18nattrs.get(key)
+ repldict[key] = None, 'text', 1, i18nattrs.get(key)
else:
repldict = {}
if replaced:
diff --git a/src/zope/tal/talinterpreter.py b/src/zope/tal/talinterpreter.py
index bac8548..98b0ed1 100644
--- a/src/zope/tal/talinterpreter.py
+++ b/src/zope/tal/talinterpreter.py
@@ -468,7 +468,7 @@ class TALInterpreter(object):
def attrAction_tal(self, item):
name, value, action = item[:3]
ok = 1
- expr, xlat, msgid = item[3:]
+ expr, repl_type, xlat, msgid = item[3:]
if self.html and name.lower() in BOOLEAN_HTML_ATTRS:
evalue = self.engine.evaluateBoolean(item[3])
if evalue is self.Default:
@@ -499,7 +499,10 @@ class TALInterpreter(object):
value = translated
if value is None:
value = name
- return ["%s=%s" % (name, quote(value))]
+ if repl_type == 'structure':
+ value = '"%s"' % value.replace('"', '&quot;')
+ else: value = quote(value)
+ return ["%s=%s" % (name, value)]
else:
return ()
bytecode_handlers["<attrAction>"] = attrAction
diff --git a/src/zope/tal/tests/test_htmltalparser.py b/src/zope/tal/tests/test_htmltalparser.py
index eb53f51..861be9c 100644
--- a/src/zope/tal/tests/test_htmltalparser.py
+++ b/src/zope/tal/tests/test_htmltalparser.py
@@ -458,11 +458,11 @@ class TALGeneratorTestCases(TestCaseBase):
{'tal:attributes': 'href string:http://www.zope.org; x string:y',
'name': 'bar', 'href': 'foo'}),
('startTag', ('a',
- [('href', 'foo', 'replace', '$string:http://www.zope.org$', 0, None),
+ [('href', 'foo', 'replace', '$string:http://www.zope.org$', 'text', 0, None),
('name', 'name="bar"'),
('tal:attributes',
'href string:http://www.zope.org; x string:y', 'tal'),
- ('x', None, 'insert', '$string:y$', 0, None)])),
+ ('x', None, 'insert', '$string:y$', 'text', 0, None)])),
('endScope', ()),
rawtext('link</a>'),
])
@@ -485,7 +485,7 @@ class TALGeneratorTestCases(TestCaseBase):
('tal:attributes', 'src string:foo.png', 'tal')]))],
[('insertStructure',
('$string:<img>$',
- {'src': ('$string:foo.png$', False, None)},
+ {'src': ('$string:foo.png$', 'text', False, None)},
[('rawtextOffset', ('duh', 3))]))])),
('endScope', ())])
@@ -578,7 +578,7 @@ class TALGeneratorTestCases(TestCaseBase):
('setPosition', (1, 0)),
('beginScope', {'alt': 'foo', 'i18n:attributes': 'alt'}),
('startTag', ('img',
- [('alt', 'foo', 'replace', None, 1, None),
+ [('alt', 'foo', 'replace', None, 'text', 1, None),
('i18n:attributes', 'alt', 'i18n')])),
('endScope', ()),
])
@@ -586,9 +586,9 @@ class TALGeneratorTestCases(TestCaseBase):
('setPosition', (1, 0)),
('beginScope', {'alt': 'foo', 'i18n:attributes': 'alt foo ; bar'}),
('startTag', ('img',
- [('alt', 'foo', 'replace', None, 1, 'foo'),
+ [('alt', 'foo', 'replace', None, 'text', 1, 'foo'),
('i18n:attributes', 'alt foo ; bar', 'i18n'),
- ('bar', None, 'insert', None, 1, None)])),
+ ('bar', None, 'insert', None, 'text', 1, None)])),
('endScope', ()),
])
diff --git a/src/zope/tal/tests/test_talinterpreter.py b/src/zope/tal/tests/test_talinterpreter.py
index d7b73ca..6d9bb3f 100644
--- a/src/zope/tal/tests/test_talinterpreter.py
+++ b/src/zope/tal/tests/test_talinterpreter.py
@@ -493,6 +493,20 @@ class I18NCornerTestCaseBase(TestCaseBase):
"Foo <span tal:replace='bar' i18n:name='bar' /></div>")
self._check(program, u"<div>FOO \u00C0</div>")
+ def test_attributes_structure(self):
+ # test that "structure" is recognized in 'tal:attributes'
+ # Note: this test does not belong here (as it has nothing to
+ # do with translation) -- however, there does not seem to be
+ # a more appropriate place
+ # Note: the example shows that we need to know which entities
+ # are replaced by the parser (there must be a single
+ # ';' after '&quot' (as the parser replaces "&quot;" by '"')
+ # but a double one after '&uuml' (as this is not replaced by parsing))
+ program, macros = self._compile(
+ '<span tal:attributes="test structure string:A&uuml;;&quot;Z"/>')
+ self._check(program, '<span test="A&uuml;&quot;Z" />')
+
+
class I18NCornerTestCaseMessage(I18NCornerTestCaseBase):
def factory(self, msgid, default=None, mapping={}, domain=None):