diff options
author | Andreas Jung <yet@gmx.de> | 2009-05-11 08:50:08 +0000 |
---|---|---|
committer | Andreas Jung <yet@gmx.de> | 2009-05-11 08:50:08 +0000 |
commit | eac40552db16e2c67e1eb3e0de028601d32e7c1d (patch) | |
tree | 99c49994f577c62d23369800c0c93e5f02866999 | |
parent | c5fb331c37e1985f23205083346a9d5ebf2caf49 (diff) | |
download | zope-tal-eac40552db16e2c67e1eb3e0de028601d32e7c1d.tar.gz |
- Launchpad #3742721 - 'structure' directive support within
tal:attributes
-rw-r--r-- | CHANGES.txt | 6 | ||||
-rw-r--r-- | src/zope/tal/taldefs.py | 6 | ||||
-rw-r--r-- | src/zope/tal/talgenerator.py | 18 | ||||
-rw-r--r-- | src/zope/tal/talinterpreter.py | 7 | ||||
-rw-r--r-- | src/zope/tal/tests/test_htmltalparser.py | 12 | ||||
-rw-r--r-- | src/zope/tal/tests/test_talinterpreter.py | 14 |
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('"', '"') + 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 '"' (as the parser replaces """ by '"') + # but a double one after 'ü' (as this is not replaced by parsing)) + program, macros = self._compile( + '<span tal:attributes="test structure string:Aü;"Z"/>') + self._check(program, '<span test="Aü"Z" />') + + class I18NCornerTestCaseMessage(I18NCornerTestCaseBase): def factory(self, msgid, default=None, mapping={}, domain=None): |