En esta sección descubriremos cómo poblar elementos con datos.
Poblando elementos
XUL provee un método con el cual creamos elementos a partir de datos proporcionados por RDF, ya sea desde un archivo RDF o desde un origen de datos interno. Mozilla suministra muchas fuentes de datos, como ser marcadores, histórico y mensajes de correo. En la próxima sección se ofrecerán más detalles sobre esto.
Normalmente los elementos tales como treeitem y menuitem serán poblados con datos. Sin embargo, si se desea pueden usarse otros elementos, aunque éstos son mas útiles en casos especiales. A pesar de ello comenzaremos con estos otros elementos ya que los árboles y los menús requieren mas código.
Para permitir la creación de elementos basados en datos RDF se necesitará proporcionar una plantilla simple, la cual será duplicada por cada elemento creado. Esencialmente, se provee únicamente el primer elemento y los restantes son construidos sobre la base de éste.
La plantilla es creada empleando el elemento template
(en), dentro del mismo pueden ubicarse los elementos que se desee utilizar para cada elemento a construir. El elemento template
debe ser colocado dentro del contenedor que contendrá los elementos construidos. Por ejemplo, si se utiliza un árbol debe colocarse el elemento template
dentro de un elemento tree
(en).
Ejemplo de plantilla simple
Tomemos un simple ejemplo donde queremos crear un botón por cada marcador de primer nivel. Mozilla ofrece una fuente de datos de marcadores por lo que ésta puede emplearse para adquirir los datos. Este ejemplo únicamente obtendrá los marcadores de primer nivel (o carpetas de marcadores) por lo que crearemos botones. Para los marcadores hijos deberemos usar un elemento que muestre datos de manera jerárquica, como un árbol o un menú.
Tanto este ejemplo como cualquier otro que haga referencia a fuentes de datos RDF internas únicamente funcionará si se lo carga desde una URL chrome, ya que por razones de seguridad Mozilla no permite el acceso a ellas desde otras procedencias.
Para ver este ejemplo se necesitará crear un paquete chrome y cargar el archivo desde allí, (se puede hacer fácilmente mirando en archivos de manifiesto) entonces se podrá ingresar la URL chrome en la barra de direcciones del navegador.
Ejemplo 1: Código Ver en funcionamiento
<vbox datasources="rdf:bookmarks" ref="NC:BookmarksRoot" flex="1"> <template> <button uri="rdf:*" label="rdf:https://home.netscape.com/NC-rdf#Name"/> </template> </vbox>
Aquí se ha creado una caja vertical que contiene una columna de botones, uno por cada marcador de primer nivel. Puede verse que la plantilla contiene un solo botón
(en), éste es utilizado como base para todos los botones que serán creados. En la imagen se observa que se creó un conjunto de botones, uno por cada marcador.
Intente añadir un nuevo marcador en el navegador manteniendo la ventana de ejemplo abierta. Notará que los botones del ejemplo son inmediatamente actualizados, puede ser necesario enfocar la ventana para que se produzca este cambio.
Contenedor y fuentes de dato
La plantilla es colocada dentro de la caja vertical, la caja posee dos atributos especiales que le permiten ser utilizada para plantillas, los cuales se emplean para especificar el origen de los datos. El primer atributo de la caja es datasources
, el cual se usa para declarar la fuente de datos RDF que proveerá los datos para crear los elementos, en éste caso rdf:bookmarks
. Se habrá adivinado que esto significa que se utilizará la fuente de datos de marcadores, esta fuente es proveída por Mozilla. Para utilizar un origen de datos propio, en el atributo datasources
debe especificarse la URL de un archivo RDF, tal como se indica en el siguiente ejemplo:
<box datasources="chrome://zoo/contenidos/animales.rdf" ref="https://www.algun-zoo-ficticio.com/todos-los-animales">
Incluso pueden especificarse múltiples fuentes de datos al mismo tiempo separándolas con un espacio en el valor del atributo. Esto puede aprovecharse para mostrar datos desde varios orígenes.
El atributo ref
indica la parte de la fuente de datos desde donde se quiere obtener los datos. En el ejemplo de los marcadores, el valor NC:BookmarksRoot
es utilizado para indicar la raíz de la jerarquía de marcadores. Otros valores posibles dependerán del origen de datos utilizado, si se utiliza un archivo RDF propio como origen de datos, el valor corresponderá al valor de un atributo about
en un elemento Bag
RDF, un elemento Seq
o un elemento Alt
.
Dentro de la plantilla
Al añadir estos dos atributos a la caja de arriba se permitirá la generación de elementos utilizando la plantilla. Sin embargo, los elementos dentro de la plantilla necesitan ser declarados de otra forma. En el ejemplo anterior puede observarse que el botón posee un atributo uri
y un valor inusual para el atributo label
.
El valor de un atributo dentro de la plantilla que comience con 'rdf:' indica que el valor debe ser obtenido de la fuente de datos, éste es el caso del atributo label
en el ejemplo anterior. El resto del valor hace referencia a la propiedad name en la fuente de datos. Esto se construye tomando la URL del área de denominación utilizada por la fuente de datos y agregando la propiedad name. Si no puede comprender esto intente volver a leer la última parte de la sección anterior, la cual explica cómo se pueden referenciar los recursos en RDF. Aquí usamos únicamente el nombre del marcador pero hay muchos otros campos disponibles.
La etiqueta de los botones es fijada a esta URI especial ya que queremos que las etiquetas en los botones contengan los nombres de los marcadores. Podríamos haber puesto una URI en cualquiera de los atributos del botón, o de cualquier otro elemento. Los valores de estos atributos son reemplazados con datos alimentados por la fuente de datos la cual es, en éste caso, la de marcadores. Por ello terminamos con las etiquetas de los botones conteniendo los nombres de los marcadores.
El siguiente ejemplo muestra cómo podríamos establecer otros atributos de un botón empleando una fuente de datos. Naturalmente, esto asume que la fuente de datos provee los recursos apropiados. Si un recurso en particular no puede ser encontrado el valor del atributo será una cadena de texto vacía.
<button class="rdf:https://www.ejemplo.com/rdf#clase" uri="rdf:*" label="rdf:https://www.ejemplo.com/rdf#name"/> crop="rdf:https://www.ejemplo.com/rdf#crop"/>
Como puede verse, es posible generar listas de elementos dinámicamente con los atributos proporcionados por un origen de datos diferente. El atributo uri es empleado para especificar el elemento a partir del cual se iniciará la generación de contenido. El primer contenido se generará una vez mientras que el contenido en el interior será generado para cada recurso. Veremos más de esto al crear plantillas para árboles.
Más ejemplos
Al agregar estas características en el contenedor dentro del cual se encuentra la plantilla, que es en este caso una caja, y a los elementos dentro de la plantilla, podremos generar listas de contenido interesantes a partir de datos externos. Claro que podemos poner más de un elemento dentro de una plantilla y añadir las referencias RDF especiales a los atributos en cualquiera de estos elementos. El siguiente ejemplo lo demuestra.
Ejemplo 2: Código Ver en funcionamiento
<vbox datasources="rdf:bookmarks" ref="NC:BookmarksRoot" flex="1"> <template> <vbox uri="rdf:*"> <button label="rdf:https://home.netscape.com/NC-rdf#Name"/> <label value="rdf:https://home.netscape.com/NC-rdf#URL"/> </vbox> </template> </vbox>
Esto crea una caja vertical con un botón y una etiqueta por cada marcador. El botón tendrá el nombre del marcador y la etiqueta su URL.
Los elementos que son creados no son funcionalmente diferentes a aquellos insertados directamente en el archivo XUL. Para cada elemento creado a través de una plantilla se añadirá el atributo id, el cual tendrá un valor que identifica el recurso. Esto puede emplearse para identificar el recurso creado.
También es posible especificar en el mismo atributo múltiples valores de recurso separándolos con un espacio, igual que en ejemplo debajo y en más acerca de la sintaxis de recursos (XULPlanet).
Ejemplo 3: Código Ver en funcionamiento
<vbox datasources="rdf:bookmarks" ref="NC:BookmarksRoot" flex="1"> <template> <label uri="rdf:*" value="rdf:https://home.netscape.com/NC-rdf#Name rdf:https://home.netscape.com/NC-rdf#URL"/> </template> </vbox>
Cómo son construidas las plantillas
Cuando un elemento posee el atributo datasources
se está indicando que se espera que el elemento sea construido a partir de una plantilla. Note que el rótulo template
no es el que determina si el contenido se construirá, es el atributo datasources
. Si este atributo está presente, un objeto llamado Builder (constructor) se añadirá al elemento. Este objeto es el responsable de construir el contenido a partir de la plantilla. En JavaScript puede accederse al objeto constructor mediante la propiedad builder
, aunque normalmente esto será necesario solo si se desea que el constructor regenere el contenido en situaciones donde esto no se haga automáticamente.
Existen dos tipos diferentes de constructores. El primero es un constructor de contenidos y se utiliza en la mayoría de los casos, y el otro es un constructor de árboles que se usa únicamente para árboles.
El constructor de contenidos toma el contenido dentro del elemento template y lo duplica por cada fila. Por ejemplo, si en el ejemplo anterior el usuario tenía diez marcadores, diez elementos label
(en) serán creados y añadidos al elemento vbox
(en). Si se utilizaran funciones DOM para recorrer el árbol, podrán encontrarse estos elementos y ver sus propiedades. Los elementos serán visibles pero no la plantilla, aunque aún existe en el documento árbol. Además, la id
de cada una de las etiquetas se establecerá con el recurso RDF para esa fila.
Este constructor siempre comienza en el lugar donde se ha especificado uri=“rdf:*�?. Si el atributo uri
en un elemento posterior al elemento árbol, los elementos fuera se crearán una sola vez. En el siguiente ejemplo se creará una caja horizontal (hbox
), la cual será llenada con una etiqueta por cada ítem.
<template> <hbox> <label uri="rdf:*" value="rdf:https://home.netscape.com/NC-rdf#Name"/> </hbox> </template>
Si hubiera otros contenidos dentro del elemento con el atributo datasources
pero fuera de la plantilla, ésos contenidos también aparecerán. Así puede mezclarse contenidos estáticos y contenidos dinámicos de una plantilla.
Constructor de árbol
El constructor de árboles, por otro lado, no genera los elementos DOM para las filas. En cambio, obtendrá la información directamente de la fuente de datos RDF cuando la necesite. Ya que usualmente se espera que los árboles muestren miles de filas de datos, este método es mucho más eficiente. Crear un elemento por cada celda sería muy costoso. Sin embargo, el trueque es que los árboles únicamente pueden mostrar texto y, como no se crean elementos, no podrán utilizarse propiedades CSS para diseñar celdas de árboles.
El constructor de árboles se utiliza solamente con árboles. Los otros elementos utilizan el constructor de contenido. Esto no causa problema alguno, ya que no se prevé que otros elementos -como los menús- contengan demasiados ítems. También es posible utilizar el constructor de contenido con los árboles, y por cada fila se crearán un elemento treeitem
y sus elementos relacionados.
Reglas, líneas o delineación
En la imagen del anterior ejemplo se habrá notado que el tercer botón es simplemente un botón con un guión adentro, éste es un separador en la lista de marcadores. De la manera en que la venimos usando, la fuente de datos RDF de marcadores suministra los separadores como si fueran comunes marcadores. Lo que realmente querríamos lograr es mostrar un pequeño espacio en lugar de un botón para los separadores, esto significa que queremos crear dos tipos diferentes de contenido, uno para los marcadores regulares y otro para los separadores.
Podemos hacer esto empleando el elemento rule
(en). Definimos una regla/línea por cada variación en los elementos que queremos crear. En nuestro caso, necesitaremos un delineación para los marcadores y otro para los separadores. Los atributos puestos en el elemento rule
determinan cuales reglas se aplican a qué recurso RDF.
Al buscarse qué delineación aplican a los datos, cada regla es revisada en secuencia buscando coincidencias. Esto significa que el orden en que se definen las delineación es importante, ya que los primeros tendrán precedencia sobre los posteriores.
El siguiente ejemplo demuestra el ejemplo anterior con dos reglas:
Ejemplo 4: Código Ver en funcionamiento
<window id="ventana-ejemplo title="Lista de marcadores" xmlns:html="https://www.w3.org/1999/xhtml" xmlns:rdf="https://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="https://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <vbox datasources="rdf:bookmarks" ref="NC:BookmarksRoot" flex="1"> <template> <rule rdf:type="https://home.netscape.com/NC-rdf#BookmarkSeparator"> <spacer uri="rdf:*" height="16"/> </rule> <rule> <button uri="rdf:*" label="rdf:https://home.netscape.com/NC-rdf#Name"/> </rule> </template> </vbox> </window>
Al utilizar dos delineaciones hemos permitido que el contenido de la plantilla sea generado selectivamente. En la primer regla se seleccionan separadores de marcadores, como puede observarse en el atributo rdf:type
. La segunda delineación no posee atributos, por lo que todos los datos corresponden.
Todos los atributos puestos en el rótulo tag se usan como criterio de correspondencia. En este caso, la fuente de datos bookmarks
provee una propiedad rdf:type
para distinguir separadores. Este atributo es fijado en un valor especial para los separadores en la fuente de datos RDF de marcadores, así es como podemos distinguirlos de los marcadores que no son separadores. Una técnica similar puede ser utilizada para cualquier atributo que pudiera existir en un elemento RDF Description
.
El valor URL específico dado al primer lineamiento en el ejemplo de arriba se utiliza para separadores. Esto significa que los separadores seguirán la regla uno y generarán un elemento spacer
, el que mostrará un hueco de 16 píxeles. Los elementos que no sean separadores no coincidirán con la regla uno y caerán en la regla dos, la cual no posee atributos por lo que cualquier dato coincide. Esto es, por supuesto, lo que queremos que le suceda al resto de la información.
Se habrá notado también que como quisimos obtener un atributo del área de denominación RDF (rdf:type
) tuvimos que añadir una declaración del área de denominación al rótulo window
. Si no hubiéramos hecho esto el atributo (type) se habría buscado en el área de denominación XUL, y como éste atributo no existe en ella la regla no tendría correspondencias. Si se utilizan atributos en un área de denominación propia se deberá añadir una declaración a la misma para corresponderlos.
Debería adivinarse qué sucedería si se eliminara la segunda delineación. Como resultado se vería un solo espacio y ningún marcador ya que los mismos no coincidirían con ninguna de las reglas.
Puesto de manera simple, una delineación corresponde si todos los atributos puestos en el elemento rule
coinciden los atributos correspondientes en el recurso RDF. En el caso de un archivo RDF, los recursos serían los elementos Description
.
Sin embargo hay pequeñas excepciones. No puede haber correspondencias basadas en los atributos id, rdf:property
o rdf:instanceOf
, aunque ya que pueden utilizarse atributos propios de áreas de denominación propias esto no debe importar mucho.
Note que una plantilla sin reglas en ella, como en el primer ejemplo, en realidad es funcionalmente un equivalente a una plantilla con un solo lineamiento sin atributos en él.
A continuación veremos cómo utilizar plantillas con los árboles.