Introducción
Cada tema del Centro de ayuda consiste en una colección de plantillas de páginas editables que determinan el diseño de los distintos tipos de páginas que componen el Centro de ayuda. Por ejemplo, hay una plantilla para los artículos de la base de conocimientos, una para la lista de solicitudes, etc.
Cada plantilla consta de una mezcla de marcado HTML y expresiones estilo Handlebars fáciles de identificar en la plantilla por sus llaves dobles. Handlebars es un motor de plantillas que permite insertar o manipular contenido en una página durante la renderización en lugar de durante el diseño.
El lenguaje de plantillas en el Centro de ayuda se llama Curlybars y es el que se encarga de implementar un extenso subconjunto del lenguaje Handlebars. Esta guía muestra cómo usar el lenguaje para personalizar las páginas del Centro de ayuda.
El Centro de ayuda proporciona helpers y propiedades con nombre para personalizar el contenido. Algunos son compartidos y están a disposición de todos en las páginas del Centro de ayuda. El resto son para usarse solo en determinadas páginas.
Ejemplo
{{#each comments}}
<li class="comment" id="{{comment_id}}">
<div class="comment-avatar {{#if author.agent}} comment-avatar-agent {{/if}}">
<img src="{{author.avatar_url}}" alt="Avatar" />
</div>
<div class="comment-container">
<header class="comment-header">
<strong class="comment-author">
{{author.name}}
</strong>
</header>
</div>
</li>
{{/each}}
El ejemplo anterior genera una lista de los usuarios que dejaron comentarios en la página. El helper each
realiza una iteración de cada valor en la propiedad comments
de la página. Por cada comentario, se insertan los valores de las propiedades author.avatar_url
y author.name
en el HTML.
Aspectos básicos de la creación de plantillas
Esta sección presenta los elementos necesarios para crear cualquier plantilla. Si desea más información, consulte Help Center Templates en developer.zendesk.com.
Una plantilla Curlybars está compuesta de dos elementos: texto que se renderiza palabra por palabra y expresiones Curlybars. Esto implica que una plantilla vacía es una plantilla válida y una plantilla que contiene solo texto también es válida. Por ejemplo, la siguiente es una plantilla válida:
<h1>Article</h1>
<p>Some details on the article</p>
Desde luego que si las plantillas del Centro de ayuda solo sirvieran para reproducir texto palabra por palabra, no se podrían personalizar durante la renderización. Para agregar lógica de plantilla, es necesario usar expresiones Curlybars, las cuales van encerradas entre llaves dobles ({{
y }}
).
Para agregar lógica de plantilla al ejemplo anterior, se podría modificar la plantilla de la siguiente manera:
<h1>Article</h1>
<p>Some details on the article</p>
{{article.author.name}}
En las secciones que siguen se explica cómo escribir expresiones válidas que permiten hacer cambios significativos a la plantilla.
Observe que encerrar un par de llaves dentro de otro par de llaves no es una sintaxis válida. Por ejemplo, no se permite lo siguiente:
<h1>Article</h1>
<p>Some details on the article</p>
{{ {{ ... }} }}
Comentarios
Existen situaciones en las que resulta útil que la plantilla cuente con notas que no se puedan escapar hacia la página renderizada. Para ello, Curlybars permite hacer comentarios colocando un signo de exclamación justo después de la llave de apertura, sin espacios: {{! ... }}
. Esta sintaxis se puede utilizar para agregar un comentario en el código como en el ejemplo que sigue:
{{!
This template aims to
show details of an article
}}
<h1>Article</h1>
<p>Some details on the article</p>
Lo que se envía al navegador una vez que la página es renderizada, es lo siguiente:
<h1>Article</h1>
<p>Some details on the article</p>
La facilidad de descartar cualquier cosa enmarcada en un comentario puede ser muy útil a la hora de crear una plantilla. Por ejemplo, los comentarios permiten excluir parte del código para hacer verificaciones, depurar, etc.
Comentarios en bloque
Sin embargo, la sintaxis descrita hasta este momento que sirve para marcar líneas como comentarios no sirve para excluir código de Curlybars. De modo que para excluir código de Curlybars (marcándolo como comentario), se debe usar esta sintaxis: {{!-- ... ---}}
. Este tipo de comentario puede abarcar varias líneas y excluir correctamente el código marcado como comentario. Ejemplo:
{{!
This template aims to
show details of an article
}}
<h1>Article</h1>
<p>Some details on the article</p>
{{!--
I want to commend out the following code:
{{ ... some Curlybars expressions }}
--}}
La plantilla anterior se renderiza de la siguiente manera:
<h1>Article</h1>
<p>Some details on the article</p>
Valores literales
Para incluir valores que Curlybars deberá interpretar textualmente, Curlybars utiliza el concepto de literales. Un literal puede representar 3 tipos de valores: una cadena, un elemento booleano y un número.
Para expresar una cadena, se pueden usar comillas simples o dobles, pero no se pueden mezclar. Por ejemplo, 'esta es una cadena válida', "esta también es válida", en cambio "esta no es válida'.
Un número puede ser cualquier entero positivo o negativo. 123
es un número positivo válido, +123
representa el mismo valor, 00123
sigue siendo válido y -123
es válido también.
Un valor booleano se representa por true
y false
. No se admite ninguna otra variación. Por ejemplo, TRUE
y FALSE
no son interpretados como valores booleanos en Curlybars.
Los elementos literales se pueden renderizar. Ejemplo:
A string: {{ 'hello world' }}
A boolean: {{ true }}
A number: {{ 42 }}
La página se renderiza de la siguiente manera:
A string: 'hello world'
A boolean: true
A number: 42
Propiedades
Cada plantilla del Centro de ayuda tiene acceso a un contexto que representa datos sobre el Centro de ayuda. Por ejemplo, la plantilla de página Article tiene un objeto llamado article
que expone la estructura del artículo solicitado por los usuarios. Para conocer todas las propiedades que se pueden usar en las plantillas, consulte Help Center Templates en developer.zendesk.com.
Emplee la notación de puntos para extraer información específica de estos objetos. Un ejemplo sencillo es article.title
.
A veces el nombre debidamente calificado de una propiedad se conoce como ruta. Por ejemplo, name
es una propiedad del objeto author
, pero article.author.name
es su ruta.
Para mostrar el valor de una propiedad debe encerrarse en llaves dobles. Y volviendo al ejemplo, quizás convenga escribir el nombre del autor en un párrafo separado:
<h1>Article</h1>
<p>Author: {{article.author.name}}</p>
Digamos que un usuario desea ver un artículo escrito por un agente llamado Juan Ventura. La plantilla se renderiza de la siguiente manera:
<h1>Article</h1>
<p>Author: John Venturini</p>
Quizás también desee renderizar el artículo propiamente dicho. El objeto article
tiene una propiedad body
que contiene el cuerpo del artículo. Entonces, habría que modificar la plantilla como sigue para renderizar el cuerpo del artículo:
<h1>Article</h1>
<p>Author: {{article.author.name}}</p>
<article>{{article.body}}</article>
Condicionales
Además de renderizar los valores de propiedad, el lenguaje de plantillas permite impartir lógica de renderización condicional a las plantillas.
Por ejemplo, quizás desee renderizar un fragmento HTML en caso de que el artículo solicitado sea interno. El contexto de la página Article tiene una propiedad article.internal
que devuelve un valor true
si el artículo es interno o un valor false
si no lo es.
Se puede crear un bloque if
con esa información. La expresión if
debe especificar una condición que puede ser verdadera o falsa. El resultado determinará si se renderiza o no el contenido del bloque. La sintaxis básica es la siguiente:
{{#if condition}}
This is rendered if the condition is true.
{{/if}}
La plantilla de ejemplo se puede modificar de esta manera:
<h1>Article</h1>
{{#if article.internal}}
<p>This article is internal.</p>
{{/if}}
<p>Author: {{article.author.name}}</p>
<article>{{article.body}}</article>
Quizás desee renderizar un bloque cuando la condición sea falsa. En ese caso, use un bloque unless
. La sintaxis es similar a la del bloque if
:
{{#unless condition}}
This is rendered if the condition is false.
{{/unless}}
Volviendo al ejemplo, supongamos que desee renderizar un mensaje cuando un artículo no sea interno. La plantilla se puede modificar de esta manera:
<h1>Article</h1>
{{#if article.internal}}
<p>This article is internal.</p>
{{/if}}
{{#unless article.internal}}
<p>This is a publicly visible article!</p>
{{/unless}}
<p>Author: {{article.author.name}}</p>
<article>{{article.body}}</article>
Este tipo de lógica condicional ("si es verdadero se hace esto y si es falso se hace lo otro") es controlada normalmente por un bloque if-else
. La sintaxis es como sigue:
{{#if condition}}
This is rendered if the condition is true.
{{else}}
This is rendered if the condition is false.
{{/if}}
El ejemplo se puede modificar de esta manera:
<h1>Article</h1>
{{#if article.internal}}
<p>This article is internal.</p>
{{else}}
<p>This is a publicly visible article!</p>
{{/if}}
<p>Author: {{article.author.name}}</p>
<article>{{article.body}}</article>
El bloque unless
también tiene una variante unless-else
, que se puede usar para lograr el mismo resultado que un bloque if-else
:
<h1>Article</h1>
{{#unless article.internal}}
<p>This is a publicly visible article!</p>
{{else}}
<p>This article is internal.</p>
{{/unless}}
<p>Author: {{article.author.name}}</p>
<article>{{article.body}}</article>
Cómo se evalúan las condiciones
Una condición es normalmente una propiedad del Centro de ayuda tal como article.internal
, que tiene un valor booleano verdadero o falso. Algunas propiedades carecen de valores booleanos. Y en ese caso se evalúan de la siguiente manera:
-
Si el valor es un número, entonces 0 da un resultado falso y cualquier otro número da un resultado verdadero
-
Si el valor es una cadena, entonces una cadena vacía da un resultado falso y cualquier otra cadena da un resultado verdadero
-
Si el valor es una colección de objetos, entonces una colección vacía da un resultado falso y cualquier otra colección da un resultado verdadero
-
Si el valor es nulo, la expresión da un resultado falso
Supongamos que le interesa implementar una lógica condicional que revise números. La página Article tiene una propiedad article.comment_count
que contiene el número total de comentarios de un artículo. Se puede usar la condición if
para ver si el recuento no está en 0
y mostrar un mensaje al respecto. Ejemplo:
<h1>Article</h1>
<p>Author: {{article.author.name}}</p>
<article>{{article.body}}</article>
{{#if article.comment_count}}
<p>Yahoo! This article has got some comments!</p>
{{/if}}
Reducción de espacios en blanco
Cuando Curlybars procesa una plantilla, el texto se reproduce palabra por palabra. Eso es bueno y casi siempre es conveniente. Sin embargo, algunas veces es necesario tener más control de los caracteres en blanco que aparecen junto a una expresión. Vea el siguiente código de ejemplo:
<a href="..." class="{{#if highlighted}} highlight {{/if}}">Click me!</a>
Renderiza el siguiente código HTML cuando highlighted
es verdadero:
<a href="..." class=" highlight ">Click me!</a>
Hay un espacio antes y después de la palabra highlight, lo cual está bien, pero supongamos que es necesario mantener los espacios en la plantilla sin renderizarlos. En ese caso se puede usar el carácter de tilde (~).
Cuando se agrega la tilde en las llaves de apertura o de cierre se eliminan los espacios en blanco del texto encerrado en ellas. Ejemplo:
<a href="..." class="{{#if highlighted~}} highlight {{~/if}}">Click me!</a>
Las tildes suprimen los espacios antes y después de la palabra highlight:
<a href="..." class="highlight">Click me!</a>
La tilde elimina los caracteres en blanco que no tienen ninguna representación gráfica pero afecta el espaciado y la división de líneas, como nuevas líneas, sangrías, retornos de carro, avances de línea, espacios sencillos y tabulaciones. Esto significa que es posible expresar el bloque if
anterior en más líneas para hacerlo más legible. Ejemplo:
<a href="..." class="
{{~#if highlighted~}}
highlight
{{~/if~}}
">Click me!</a>
Esto se sigue renderizando de esta manera:
<a href="..." class="highlight">Click me!</a>
En la vida real estos ejemplos no sirven de mucho, pero la eficacia de usar la tilde puede variar de un caso a otro.
Helpers
En algunas plantillas lo único que se necesita es acceder a los datos, mostrarlos y agregar un poco de lógica condicional. Pero se les puede agregar un poco de funcionalidad. Por ejemplo, quizás le interese mostrar una cadena localizada que cambie de acuerdo a la región del solicitante de la página. O quizás le interese recortar un fragmento de texto largo.
Este tipo de funcionalidad para las plantillas se puede conseguir gracias a los helpers. Para conocer todos los helpers que se pueden usar en las plantillas, consulte Help Center Templates en developer.zendesk.com.
Por ejemplo, se puede usar un helper llamado excerpt
en la plantilla de página Article para truncar cadenas. En el ejemplo del artículo, supongamos que se necesita mostrar una versión truncada del título del artículo. Para ello, la plantilla se puede modificar de esta manera:
<h1>{{excerpt article.title characters=50}}</h1>
<p>Author: {{article.author.name}}</p>
<article>{{article.body}}</article>
En el ejemplo anterior se puede ver el uso de llaves para invocar un helper. El helper excerpt
admite un parámetro que consiste en una expresión que se resolverá en una cadena. El helper cuenta con una opción characters
que especifica el número de caracteres que se deben mantener. La opción characters
no es obligatoria. Si no se especifica, se usará un valor predeterminado. Consulte el apartado excerpt en Help Center Templates para obtener más información.
La sintaxis para invocar un helper es la siguiente: {{<helper> [<param> ...] [<key=value> ...]}}
. El único elemento obligatorio es el nombre del helper. Los parámetros y las opciones varían según el helper.
Ahora vamos a suponer que se desea actualizar la plantilla para que muestre un mensaje de aprobación si el nombre del autor es Juan Ventura. Lamentablemente no se puede usar la condición if
para comprobar si article.author.name
es igual a "Juan Ventura" porque if
solo funciona en una expresión. Y los operadores de comparación como ==
no están disponibles.
¿Entonces, cómo insertar esa lógica? Por suerte, se puede usar el helper is
que permite tomar dos parámetros y compararlos para ver si son iguales. Ejemplo:
<h1>{{excerpt article.title characters=50}}</h1>
{{#is article.author.name 'John Venturini'}}
<p>Cool! John Venturini is the author of this article!</p>
{{/is}}
<article>{{article.body}}</article>
El fragmento anterior renderiza el mensaje de aprobación si el autor es Juan Ventura. Pero ¿qué pasa si se quiere renderizar un mensaje diferente si no es él? Lo bueno es que is
también puede incluir un bloque else
, tal como en la declaración if-else
. Para restaurar el mensaje anterior si el autor no es Juan Ventura, se puede agregar un bloque else
como sigue:
<h1>{{excerpt article.title characters=50}}</h1>
{{#is article.author.name 'John Venturini'}}
<p>Cool! John Venturini is the author of this article!</p>
{{else}}
<p>Author: {{article.author.name}}</p>
{{/is}}
<article>{{article.body}}</article>
Cambio de ámbito
El acceso a los datos es muy sencillo si se usa la notación de puntos, especialmente cuando la ruta a la información que necesitamos no es demasiado larga. Ejemplo: article.title
. Cabe notar que en algunas circunstancias quizás sea necesario acceder a una propiedad con una ruta más extensa. Ejemplo: article.author.name
. Opcionalmente, se pueden usar rutas más extensas en las plantillas. Por ejemplo, se puede agregar el nombre del autor y su avatar como en el ejemplo que sigue:
<h1>{{excerpt article.title characters=50}}</h1>
<img src="{{article.author.avatar_url}}" alt="Author's avatar" height="42" width="42">
{{#is article.author.name 'John Venturini'}}
<p>Cool! John Venturini is the author of this article!</p>
{{else}}
<p>Author: {{article.author.name}}</p>
{{/is}}
<article>{{article.body}}</article>
El fragmento anterior está perfecto, pero las rutas de propiedades extensas hacen que el código se vea un poco sobrecargado. Una manera de resolver este problema es a través de un construct especial with
. with
admite un parámetro que representa el contexto de base que debe utilizarse en el bloque de código asociado con él. La sintaxis es como sigue:
{{#with <context>}}
...
{{/with}}
El ejemplo se puede mejorar de esta manera:
<h1>{{excerpt article.title characters=50}}</h1>
{{#with article.author}}
<img src="{{avatar_url}}" alt="Author's avatar" height="42" width="42">
{{#is name 'John Venturini'}}
<p>Cool! John Venturini is the author of this article!</p>
{{else}}
<p>Author: {{name}}</p>
{{/is}}
{{/with}}
<article>{{article.body}}</article>
El parámetro article.author
elimina la necesidad de incluir article.author
en las rutas del bloque. De modo que {{name}}
dentro del bloque equivale a article.author.name
fuera del bloque.
No se puede utilizar article.author.name
en el bloque porque sería evaluado como article.author.article.author.name
. De modo semejante, no se puede obtener acceso al título del artículo en el bloque mediante article.title
porque el objeto article es accesible solo en el contexto raíz que se encuentra fuera del bloque.
Para escaparse del contexto establecido por with
y acceder al contexto exterior, use la notación ../
en la ruta. Es posible renderizar el título del artículo dentro del bloque with
de esta manera:
<h1>{{excerpt article.title characters=50}}</h1>
{{#with article.author}}
{{../article.title}}
<img src="{{avatar_url}}" alt="Author's avatar" height="42" width="42">
{{#is name 'John Venturini'}}
<p>Cool! John Venturini is the author of this article!</p>
{{else}}
<p>Author: {{name}}</p>
{{/is}}
{{/with}}
<article>{{article.body}}</article>
La notación ../
se puede usar reiteradamente en la misma ruta. Se regresará el mismo número de contextos. Por ejemplo, en el siguiente contexto, funcionará tal como es de esperarse:
<h1>{{excerpt article.title characters=50}}</h1>
{{#with article}}
{{#with author}}
{{../../article.title}}
...
{{/with}}
<article>{{article.body}}</article>
Y para ir más allá y renderizar un determinado mensaje cuando no se especifique el autor, se puede optar por un bloque if
así:
<h1>{{excerpt article.title characters=50}}</h1>
{{#if article.author}}
{{#with article.author}}
...
{{/with}}
{{else}}
No author is present for this article!
{{/if}}
<article>{{article.body}}</article>
Cabe señalar que en el Centro de ayuda article.author
nunca tiene un valor nulo. Aquí se interpreta así solo para propósitos del ejemplo.
El fragmento anterior funciona muy bien, pero se puede conseguir el mismo resultado con un bloque else
en el construct with
. El bloque else se ejecuta si el parámetro es 'falsy'. El ejemplo se puede modificar de esta manera:
<h1>{{excerpt article.title characters=50}}</h1>
{{#with article.author}}
...
{{else}}
No author is present for this article!
{{/with}}
<article>{{article.body}}</article>
El uso de un bloque else
también permite que el código sea más legible.
Transferencia del contexto raíz a un helper
Use la palabra clave this
para transferir el contexto raíz actual a un helper. Supongamos que tiene un helper render_author
que admite un objeto article
como parámetro con el propósito de mostrar los detalles de su autor. Se puede usar la palabra clave this
de la siguiente manera:
<h1>{{excerpt article.title characters=50}}</h1>
{{#with article}}
{{render_author this}}
{{/with}}
<article>{{article.body}}</article>
this
se resolverá como article
.
Acceso a los elementos de una matriz
Algunas propiedades del Centro de ayuda consisten en matrices de objetos. Por ejemplo, la propiedad attachments
consta de una matriz de adjuntos.
Para acceder a los elementos de una matriz, deberá iterar encima de cada uno. Eso es precisamente lo que hace el helper each
. Ejemplo:
<h1>{{excerpt article.title characters=50}}</h1>
{{#with article.author}}
...
{{/with}}
<article>{{article.body}}</article>
{{#each attachments}}
<a href="{{url}}" target="_blank">{{name}}</a>
<span>({{size}})</span>
{{/each}}
En el fragmento anterior se pueden ver todos los adjuntos. Cada elemento muestra los datos específicos de un adjunto, por ejemplo url
, name
y size
.
Al igual que with
, each
cambia el contexto en ese bloque. Esto quiere decir que para acceder al contexto exterior, habría que usar la notación ../
.
Quizás desee renderizar un mensaje cuando una matriz esté vacía. Eso se puede conseguir fácilmente usando un bloque if
de la siguiente manera:
...
{{#if attachments}}
{#each attachments}}
<a href="{{url}}" target="_blank">{{name}}</a>
<span>({{size}})</span>
{{/each}}
{{else}}
Sorry, no attachments available!
{{/if}}
Esto funciona perfectamente bien, pero también se puede usar un bloque else
para que el código sea más legible:
...
{#each attachments}}
<a href="{{url}}" target="_blank">{{name}}</a>
<span>({{size}})</span>
{{else}}
Sorry, no attachments available!
{{/each}}
Longitud
Cada matriz cuenta con una propiedad length
implícita que proporciona el número de elementos en la matriz. Por ejemplo, si desea mostrar el número de adjuntos, use la propiedad length
de la siguiente manera:
...
There are {{attachments.length}}.
{#each attachments}}
<a href="{{url}}" target="_blank">{{name}}</a>
<span>({{size}})</span>
{{/each}}