--- a/src/pyams_utils/tales.py Tue Nov 15 10:43:55 2016 +0100
+++ b/src/pyams_utils/tales.py Fri Nov 18 15:28:54 2016 +0100
@@ -27,7 +27,7 @@
class ContextExprMixin(object):
- """Mixin-class for expression compilers."""
+ """Mixin-class for expression compilers"""
transform = None
@@ -44,22 +44,92 @@
ARGUMENTS_EXPRESSION = re.compile('[^(,)]+')
-def get_value(econtext, arg):
- """Extract argument value from context"""
- arg = arg.strip()
- if arg.startswith('"') or arg.startswith("'"):
- # may be a quoted string...
- return arg[1:-1]
- args = arg.split('.')
- result = econtext.get(args.pop(0))
- for arg in args:
- result = getattr(result, arg)
- return result
+def render_extension(econtext, name):
+ """TALES extension renderer
+
+ This renderer can be used to render an *extension:* TALES expression.
+ When this expression is encountered, the renderer is looking for an
+ :py:class:`ITALESExtension <pyams_utils.interfaces.tales.ITALESExtension>`
+ multi-adapter for the current *context*, *request* and *view*, for the current
+ *context* and *request*, or only for the current *context*, in this order.
+ If an adapter is found, the renderer call it's :py:func:`render` method with
+ the expression parameters as input parameters.
+
+ For example, the *metas* extension is an *ITALESExtension* adapter defined into
+ :py:mod:`pyams_skin.metas` module which can be used to include all required headers in
+ a page template. Extension is used like this in the page layout template:
+
+ .. code-block:: html
+
+ <tal:var replace="structure extension:metas" />
+
+ This extension is defined like this:
+
+ .. code-block:: python
+
+ from pyams_skin.interfaces.metas import IHTMLContentMetas
+ from pyams_utils.interfaces.tales import ITALESExtension
+ from pyramid.interfaces import IRequest
+
+ from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter
+
+ @adapter_config(name='metas', context=(Interface, IRequest, Interface), provides=ITALESExtension)
+ class MetasTalesExtension(ContextRequestViewAdapter):
+ '''extension:metas TALES extension'''
+
+ def render(self, context=None):
+ if context is None:
+ context = self.context
+ result = []
+ for name, adapter in sorted(self.request.registry.getAdapters((context, self.request, self.view),
+ IHTMLContentMetas),
+ key=lambda x: getattr(x[1], 'order', 9999)):
+ result.extend([meta.render() for meta in adapter.get_metas()])
+ return '\n\t'.join(result)
+ Some TALES extension can require or accept arguments. For example, the *absolute_url* extension can accept
+ a context and a view name:
-def render_extension(econtext, name):
+ .. code-block:: html
+
+ <tal:var define="logo config.logo">
+ <img tal:attributes="src extension:absolute_url(logo, '++thumb++200x36.png');" />
+ </tal:var>
+
+ The extension is defined like this:
+
+ .. code-block:: python
+
+ from persistent.interfaces import IPersistent
+ from pyams_utils.interfaces.tales import ITALESExtension
+
+ from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter
+ from pyramid.url import resource_url
+ from zope.interface import Interface
+
+ @adapter_config(name='absolute_url', context=(IPersistent, Interface, Interface), provides=ITALESExtension)
+ class AbsoluteUrlTalesExtension(ContextRequestViewAdapter):
+ '''extension:absolute_url(context, view_name) TALES extension'''
+
+ def render(self, context=None, view_name=None):
+ if context is None:
+ context = self.context
+ return resource_url(context, self.request, view_name)
+ """
+
+ def get_value(econtext, arg):
+ """Extract argument value from context"""
+ arg = arg.strip()
+ if arg.startswith('"') or arg.startswith("'"):
+ # may be a quoted string...
+ return arg[1:-1]
+ args = arg.split('.')
+ result = econtext.get(args.pop(0))
+ for arg in args:
+ result = getattr(result, arg)
+ return result
+
name = name.strip()
-
context = econtext.get('context')
request = econtext.get('request')
view = econtext.get('view')