15. Zope Page Templates

Plantillas de páginas son archivos HTML con alguna información adicional, escritas en TAL, METAL y TALES.

Las plantillas de página debe ser XML válido.

Los tres lenguajes son:

  • TAL: “Template Attribute Language”
    • Plantillas XML / HTML usando con atributos especiales

    • Usando TAL nosotros podemos incluir expresiones en HTML

  • TALES: “TAL Expression Syntax”
    • Define la sintaxis y la semántica de estas expresiones

  • METAL: “Macro Expansion for TAL”
    • esto nos permite combinar, la reutilización y las plantillas anidadas juntas

TAL y METAL se escriben como atributos HTML (url, src, title). TALES están escritos como los valores de los atributos de HTML. Una declaración TAL típica tiene este aspecto:

<title tal:content="context/title">
    The Title of the content
</title>

Se utiliza para modificar la salida:

<p tal:content="string:I love red">I love blue</p>

resultado en:

<p>I love red</p>

Vamos a intentarlo. Abra el archivo demoview.pt y agregue:

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
      lang="en"
      i18n:domain="ploneconf.site">
<body>

    <p>red</p>

</body>
</html>

TAL y TALES

Vamos a añadir un poco de magia y modificar la etiqueta <p>:

<p tal:content="string:blue">red</p>

Esto resultará en el siguiente código HTML:

<p>blue</p>

Sin reiniciar Plone abra en el navegador http://localhost:8080/Plone/@@demoview.

Lo mismo ocurre con los atributos. Remplace en la línea <p> con el siguiente código:

<a href="http://www.mssharepointconference.com"
   tal:define="a_fine_url string:http://www.ploneconf.org"
   tal:attributes="href a_fine_url"
   tal:content="string:A even better conference">
    A sharepoint conference
</a>

resultado en:

<a href="http://www.ploneconf.org">
    A even better conference
</a>

Nosotros hemos utilizado los tres atributos TAL aquí. Esta es la lista completa de los atributos TAL:

tal:define

definir las variables. Nosotros definimos la variable url para la cadena “http://www.ploneconf.org

tal:content

reemplazar el contenido de un elemento. Hemos sustituido el valor por defecto de contenido con algunas como “A even better conference”

tal:attributes

cambiar dinámicamente atributos de los elementos. Nosotros hemos establecido el atributo href html a la variable a_fine_url

tal:condition

pruebas, si la expresión es verdadera o falsa.

tal:repeat

repite un elemento iterable, en nuestro caso, la lista de charlas.

tal:replace

reemplazar el contenido de un elemento como tal:content , pero se elimina el elemento sólo dejando el contenido.

tal:omit-tag

eliminar un elemento, dejando el contenido del elemento.

tal:on-error

controlar los errores.

Expresiones Python

Hasta ahora sólo utilizamos una expresión TALES (el bit string:). Usemos una expresión TALES diferente ahora. Con python: podemos usar código python. Un ejemplo sencillo:

<p tal:define="title context/title"
   tal:content="python:title.upper()">
   A big title
</p>

Y otro ejemplo:

<p tal:define="talks python:['Dexterity for the win!',
                             'Deco is the future',
                             'A keynote on some weird topic',
                             'The talk that I did not submit']"
   tal:content="python:talks[0]">
    A talk
</p>

Con expresiones python

  • sólo se puede escribir declaraciones individuales

  • usted podría importar cosas pero no debe (ejemplo: tal:define="something modules/Products.PythonScripts/something;).

tal:condition

tal:condition

pruebas, si la expresión es verdadera o falsa.

  • Si es true, entonces la etiqueta se representa.

  • Si es false, entonces la etiqueta y todos sus hijos se retiran y ya no se evalúa.

  • Podemos invertir la lógica anteponiendo un not: a la expresión.

Vamos a añadir otro atributo TAL para nuestro ejemplo anterior:

tal:condition="talks"

También pudimos probar que el número de charlas:

tal:condition="python:len(talks) >= 1"

o si una cierta charla está en la lista de charlas:

tal:condition="python:'Deco is the future' in talks"

tal:repeat

Probemos otra sentencia:

<p tal:define="talks python:['Dexterity for the win!',
                             'Deco is the future',
                             'A keynote on some weird topic',
                             'The talk that I did not submit']"
   tal:repeat="talk talks"
   tal:content="talk">
   A talk
</p>
tal:repeat

repite un elemento iterable, en nuestro caso, la lista de charlas.

Cambiamos el formato un poco para construir una lista en la que hay una lista <li> para cada charla:

<ul tal:define="talks python:['Dexterity for the win!',
                              'Deco is the future',
                              'A keynote on some weird topic',
                              'The talk that I did not submit']">
    <li tal:repeat="talk talks"
        tal:content="talk">
          A talk
    </li>
    <li tal:condition="not:talks">
          Sorry, no talks yet.
    </li>
</ul>

Expresiones de rutas

En cuanto TALES hasta ahora hemos utilizado la string: o python: o sólo las variables. La expresión siguiente y más comunes son de path-expressions. Opcionalmente se puede iniciar path-expression con el path:

Cada expresión de ruta comienza con un nombre de variable. Puede ser tanto un objeto como context, view, template o una variable definida anteriormente como charla.

Después de la variable se añade una barra / y el nombre de un sub-objeto, atributo o método invocable. El carácter ‘/’ se utiliza para terminar el nombre de un objeto y el inicio del nombre de la propiedad. Mismas propiedades pueden ser objetos que a su vez tienen propiedades.

<p tal:content="context/title"></p>

Nos puede encadenar varios de los elementos para obtener la información que queremos.

<p tal:content="context/REQUEST/form"></p>

Esto devolverá el valor de la forma de diccionario del objeto HTTPRequest. Útil para la forma de manipulación.

El carácter | (operador lógico “o”) se utiliza para encontrar un valor alternativo a un camino si la primera ruta se evalúe como nothing o no existe.

<p tal:content="context/title | context/id"></p>

Esto devuelve el id del contexto si no tiene título.

<p tal:replace="talk/average_rating | nothing"></p>

Esto devuelve nada si no hay ‘average_rating’ para una charla. Lo que no funciona es tal:content="python:talk['average_rating'] or ''". ¿Quién sabe lo que esto produciría?

Conseguiremos KeyError: 'average_rating'. Es muy mala práctica, use el carácter | con demasiada frecuencia, ya que se tragará errores como un error tipográfico en tal:content="talk/averange_ratting | nothing" y es posible que se preguntan por qué no existen calificaciones más tarde...

No puede y no debe utilizarlo para evitar errores como un bloque try / except.

Hay varias variables incorporado que se pueden utilizar en caminos:

El más utilizado es nothing que es el equivalente a None

<p tal:replace="nothing">
    this comment will not be rendered
</p>

Un diccionario de todas las variables disponibles es CONTEXTS

<dl tal:define="path_variables_dict CONTEXTS">
  <tal:vars tal:repeat="variable path_variables_dict">
    <dt tal:content="variable"></dt>
    <dd tal:content="python:path_variables_dict[variable]"></dd>
  </tal:vars>
</dl>

Muy útil para depuración :-)

Puro bloques TAL

Podemos utilizar atributos TAL sin marcas HTML. Esto es útil cuando no es necesario añadir las etiquetas para el marcado

Sintaxis:

<tal:block attribute="expression">some content</tal:block>

Ejemplos:

<tal:block define="id template/id">
...
  <b tal:content="id">The id of the template</b>
...
</tal:block>

<tal:news condition="python:context.content_type == 'News Item'">
    This text is only visible if the context is a News Item
</tal:news>

Manejo de datos complejos en plantillas

Vamos a pasar a un poco más complejo de datos. Y a otro atributo TAL:

tal:replace

reemplazar el contenido de un elemento y elimina el elemento dejando sólo el contenido.

Ejemplo:

<p>
    <img tal:define="tag string:<img src='https://plone.org/logo.png'>"
         tal:replace="tag">
</p>

este resulta en:

<p>
    &lt;img src='https://plone.org/logo.png'&gt;
</p>

tal:replace cae su propia base de etiquetas a favor del resultado de la expresión TALES. Por lo tanto el original <img... > se sustituye. Pero el resultado se escapó por defecto.

Para prevenir que se escapen utilizamos structure

<p>
    <img tal:define="tag string:<img src='https://plone.org/logo.png'>"
         tal:replace="structure tag">
</p>

Ahora vamos a emular una estructura típica Plone mediante la creación de un diccionario.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
  <table tal:define="talks python:[{'title':'Dexterity for the win!',
                                    'subjects':('content-types', 'dexterity')},
                                   {'title':'Deco is the future',
                                    'subjects':('layout', 'deco')},
                                   {'title':'The State of Plone',
                                    'subjects':('keynote',) },
                                   {'title':'Diazo designs dont suck!',
                                    'subjects':('design', 'diazo', 'xslt')}
                                  ]">
      <tr>
          <th>Title</th>
          <th>Topics</th>
      </tr>
      <tr tal:repeat="talk talks">
          <td tal:content="talk/title">A talk</td>
          <td tal:define="subjects talk/subjects">
              <span tal:repeat="subject subjects"
                    tal:replace="subject">
              </span>
          </td>
      </tr>
  </table>

Nosotros emulamos una lista de charlas y mostrar información en una tabla. Nos pondremos en contacto a la lista de las charlas más tarde, cuando se utilizan los verdaderos objetos charlas que hemos creado con dexterity.

Para completar la lista que aquí están los atributos TAL que no hemos utilizado todavía:

tal:omit-tag

Omite las etiquetas de los elementos, dejando sólo el contenido interno.

tal:on-error

controlar los errores.

Cuando un elemento tiene múltiples sentencias, se ejecutan en este orden:

  1. define
  2. condition
  3. repeat
  4. content o replace

  5. attributes
  6. omit-tag

METAL y macros

¿Por qué nuestra vista es tan feo?, ¿Cómo conseguimos nuestro HTML para representar en la interfaz de usuario de Plone?

Utilizamos METAL (extensión macro para TAL) para definir ranuras que podemos llenar y macros que podemos reutilizar.

Agregamos a la etiqueta <html>:

metal:use-macro="context/main_template/macros/master"

Y a continuación, ajustar el código que queremos poner en el área de contenido de Plone en:

<metal:content-core fill-slot="content-core">
    ...
</metal:content-core>

Esto pondrá a nuestro código de una sección definida en el main_template llamado “content-core”.

Ahora la plantilla debería tener el siguiente aspecto:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
      lang="en"
      metal:use-macro="context/main_template/macros/master"
      i18n:domain="ploneconf.site">
<body>

<metal:content-core fill-slot="content-core">

<table tal:define="talks python:[{'title':'Dexterity for the win!',
                                  'subjects':('content-types', 'dexterity')},
                                 {'title':'Deco is the future',
                                  'subjects':('layout', 'deco')},
                                 {'title':'The State of Plone',
                                  'subjects':('keynote',) },
                                 {'title':'Diazo designs are great',
                                  'subjects':('design', 'diazo', 'xslt')}
                                ]">
    <tr>
        <th>Title</th>
        <th>Topics</th>
    </tr>
    <tr tal:repeat="talk talks">
        <td tal:content="talk/title">A talk</td>
        <td tal:define="subjects talk/subjects">
            <span tal:repeat="subject subjects"
                  tal:replace="subject">
            </span>
        </td>
    </tr>
</table>

</metal:content-core>

</body>
</html>

Nota

Desde la vista demoview solamente es utilizada el contenido de la plantilla, no por el contexto que le toca no tiene mucho sentido tener la barra de edición. Nos lo ocultamos estableciendo la variable correspondiente en el request actual con el python a 1: request.set('disable_border', 1).

La manera más fácil de hacer esto es definir una variable dummy. Dummy porque nunca se usa, salvo que nos permita ejecutar algún código.

<metal:block fill-slot="top_slot"
    tal:define="dummy python:request.set('disable_border', 1)" />

Macros en browser-views

Define un macro en un nuevo archivo macros.pt

<div metal:define-macro="my_macro">
    <p>I can be reused</p>
</div>

Registrarlo como un BrowserView (esta vez sin una clase Python) en sentencias ZCML:

<browser:page
  for="*"
  name="ploneconf.site.macros"
  template="templates/macros.pt"
  permission="zope2.View"
  />

Reuse el macro en la plantilla demoview.pt:

<div metal:use-macro="view/context/@@ploneconf.site.macros/my_macro">
    Instead of this the content of the macro will appear...
</div>

Accediendo a Plone desde la plantilla

En nuestra plantilla tenemos acceso al objeto de contexto en el que la vista se llama en adelante, la propia browser-views (es decir, todos los métodos de python vamos a poner en el punto de vista más adelante), los objetos request y response y con ellas podemos conseguir casi cualquier cosa.

En las plantillas también podemos acceder a otras browser-views. Algunos de los que existen para facilitar el acceso a los métodos que a menudo necesitamos:

tal:define="context_state context/@@plone_context_state;
            portal_state context/@@plone_portal_state;
            plone_tools context/@@plone_tools;
            plone_view context/@@plone;"
@@plone_context_state

El BrowserView plone.app.layout.globals.context.ContextState tiene métodos útiles que tienen que ver con el objeto de contexto actual como is_default_page

@@plone_portal_state

El BrowserView plone.app.layout.globals.portal.PortalState tiene métodos para el portal como portal_url

@@plone_tools

El BrowserView plone.app.layout.globals.tools.Tools da acceso a las herramientas más importante como el plone_tools/catalog

Estos son muy utilizados y hay muchos más.

Lo que echamos de menos

Hay algunas cosas que no nos cubrimos hasta el momento:

tal:condition="exists:expression"

comprueba si existe un objeto o un atributo (rara vez utilizada)

tal:condition="nocall:context"

que explícitamente no llamar a un método invocable.

Si nos referimos a objetos de contenido sin usar el modificador nocall: estos objetos son innecesariamente representados en la memoria como la expresión se evaluada.

i18n:translate y i18n:domain

las cadenas que ponemos en las plantillas se pueden traducir de forma automática.

Hay mucho más acerca de TAL, TALES y METAL que no hemos cubierto. Usted solamente aprenderá si sigues leyendo, escribiendo y personalización de plantillas.

Chameleon

Chameleon es el sucesor de TAL y serán incorporado en Plone 5.

En Plone 4 nosotros usaremos ZPT por defecto.