src/source/tales.rst
changeset 99 b2be9a32f3fc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/source/tales.rst	Thu Dec 06 08:24:10 2018 +0100
@@ -0,0 +1,74 @@
+.. _tales:
+
+Custom TALES extensions
+=======================
+
+PyAMS defines a custom expression for TALES called *extension*.
+
+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 extensions can require or accept arguments. For example, the *absolute_url* extension can accept
+a context and a view 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)