Getting started with the Style Project
From WebRatio WebML Wiki
|
The purpose of this article is to provide the basics to operate with styles in WebRatio.
A Style Project contains the layout templates needed to generate the graphical elements of your Web Application; the project includes also the resources used in the templates.
Contents |
Layout Templates
Every page in WebRatio has its associated style and can be seen as composed of several kinds of elements:
- Grid
- Cell
- Frame
- Unit
- Attribute
- Field
- Link
A template is a file containing the graphical specification of a particular type of element. Some layout elements contain other elements and therefore their templates will refer to the contained elements' templates, much like a tree. Like the layers of an onion, every template participates in the definition of the combined page layout. The content of the generated pages is not limited to markup (for example, HTML or WML), but can include any sort of client-side components, like Flash movies, Java applets, or ActiveX controls, and any sort of client-side scripting instructions, like JavaScript or VBScript routines.
Basically, a layout template is a mix of different languages: markup languages, client-side components, Groovy expressions/scriptlets and custom tags. The Groovy scriptlets and expressions look for some elements in the Web Model specification (for instance, the occurrence of an index unit) and produce the output based on the matching elements (for example, the HTML code for rendering the index unit).
The page generation process
All the pages generated by WebRatio are standard JSP pages and are obtained thru a specific process, involving generation and compiling steps:
- each element composing a page is expanded and enriched generating a Layout XML according to the Web Model
- each template associated to the elements composing the page is recalled (page template, grid template, cell template, frame template, unit template, etc.)
- every templates receives as input the corrisponding piece of XML
- WR tags are expanded in the corresponding Groovy code and are executed along with the other Groovy scriplets contained in the templates
- the result is a JSP page generated in the deploy folder composed by JSP and JSTL code
- at run-time, the JSP code and JSTL tags are evaluated, basing on the data contained in the units beans
It's important to note that Groovy scriplets and WR tags are evaluated only during generation phase (basing on layout XML), returning pages containing only JSP and JSTL tags (that are evaluated at run-time, basing on data contained in beans).
WR Tags
In addition to all the standard Web editing languages mentioned above, WebRatio provides a specific tag-based language to enable for easy composition of the templates, using information from the Web Model, like units placed on the grid, values, landmark links, etc. These tags (named WR Tags) are precompilated at generation-time evaluating the auto-generated layout XML of the Web Model resulting in standard JSP code. Here's a list of the main WR Tags:
- <wr:PageTitle/>: Prints the title of the page. Useful within the HTML <title> tag
- <wr:Grid/>: Specifies where the grid containing units has to be expanded. Usually placed in the main area of the HTML <body>
- <wr:Frame>: Prints out the frame layout for a unit or a cell, if defined
- <wr:Iterate var="..." varIndex="..." context="..." select="..." range="...">: Iterates over a list of elements. Equivalent to the following scriptlet:
[% for (<var> in <context>.selectNodes("<select>")) { %] .. [% } %] - <wr:Value context="..."/>: Prints the value of an element (attribute, field, or link)
- <wr:Link context="..."/>: Produces the HTML anchor for a specific link
Using these tags it is possible to implement standard JSP pages, compiled by the application server and executed to produce the application pages.
Here's an example of a page template:
#?delimiters [%, %], [%=, %] <!-- delimiters for Groovy scriplets -->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
[%setHTMLOutput()%]
<!-- libraries used in the page -->
<%@ taglib prefix="bean" uri="http://struts.apache.org/tags-bean" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="html" uri="http://struts.apache.org/tags-html" %>
<%@ taglib prefix="webratio" uri="http://www.webratio.com/2006/TagLib/JSP20" %>
<%@ taglib prefix="FCK" uri="http://fckeditor.net/tags-fckeditor" %>
<%@ page contentType="text/html; charset=UTF-8"%>
<webratio:Page page="<wr:PageId/>"/> <!-- declaration of the page -->
<html>
<head>
<title><wr:PageTitle/></title> <!-- prints the page title, the name of the page in the model -->
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<wr:LinkedResources/> <!-- links to CSS or JS resources declared in the project -->
</head>
<body>
<wr:PageForm> <!-- adds a global form if the page includes at least one form-based unit -->
<table width="100%" style="align:right">
<tr>
<td width="100%"></td>
<wr:LandmarkPageMenu level="1"> <!-- iterates over top-level landmark pages -->
<td nowrap="nowrap"><wr:Link/></td> <!-- generates the HTML anchor for a specific link -->
</wr:LandmarkPageMenu>
</tr>
<tr>
<td width="100%"></td>
<wr:PageLinks> <!-- iterates over all non contextual links departing from the current page -->
<td nowrap="nowrap"><wr:Link/></td>
</wr:PageLinks>
</tr>
</table>
<table width="100%">
<tr>
<td align="center"><h1><wr:PageTitle/></h1></td>
</tr>
</table>
<table>
<tr>
<wr:LandmarkAreaMenu level="1"> <!-- iterates over top-level landmark areas visible in the current Site View -->
<td nowrap="nowrap"><wr:Link/></td>
</wr:LandmarkAreaMenu>
<wr:LandmarkOperationMenu level="1"> <!-- iterates over all top-level landmark operations visible in the current area -->
<td nowrap="nowrap"><wr:Link/></td>
</wr:LandmarkOperationMenu>
</tr>
</table>
<br>
<table>
<tr>
<td>
<wr:NavigationBar separator=">"/>><wr:PageTitle/> <!-- generates the navigation bar, which is a text span containing a sequence of anchors, displaying the names of the areas enclosing the current page -->
</td>
</tr>
</table>
<table width="100%" valign="top">
<tr>
<td>
<wr:Grid/> <!-- specifies where the grid containing units has to be expanded -->
</td>
<td>
<wr:CustomLocation name="location1"/> <!-- defines a named location as an additional place for displaying units -->
</td>
</tr>
</table>
</wr:PageForm>
</body>
</html>
Unit Templates
Every unit is based on a Java Bean ("bean" for short) containing all the data of the unit. WR Tags can access to unit beans in order to show data as specified in the unit template. Using Groovy, it is possible to include scriplets inside the template that customize the layout of part of the unit.
A bean is a data structure representing the runtime state of a unit (current data) and contains all the element to be shown or used in rendering the unit on the page. The design-time structure of every unit (name, attributes, sub-units, etc.) used for generating the layout is specified in its Layout XML.
The following example shows an usual Data Unit Layout XML:
<layout:Unit xmlns:layout="http://www.webratio.com/2006/WebML/Layout"
unitId="dau1" label="Product details" _sel="t" layout:expanded="true"
id="dau1" name="Product details" entity="ent1"
xmlns:gr="http://www.webratio.com/2006/WebML/Graph"
gr:x="0" gr:y="32" displayAttributes="att10 att8 att11 att9 att12"
unitTagName="DataUnit">
<layout:Attribute attribute="att10" _sel="t" name="name" id="att10" type="string"
xmlns:db="http://www.webratio.com/2006/WebML/Database" db:column="name"/>
<layout:Attribute attribute="att8" _sel="t" name="code" id="att8" type="integer"
xmlns:db="http://www.webratio.com/2006/WebML/Database" db:column="code"/>
<layout:Attribute attribute="att11" _sel="t" name="price" id="att11" type="float"
xmlns:db="http://www.webratio.com/2006/WebML/Database" db:column="price"/>
<layout:Attribute attribute="att9" _sel="t" name="description" id="att9" type="text"
xmlns:db="http://www.webratio.com/2006/WebML/Database" db:column="description"/>
<layout:Attribute attribute="att12" _sel="t" name="thumbnail" id="att12" contentType="image"
type="blob" xmlns:db="http://www.webratio.com/2006/WebML/Database"
db:column="thumbnail"/>
<layout:Link link="ln6" _sel="t" id="ln6" name="More images" to="dau2" type="normal"
validate="true" gr:bendpoints="" keywordOrder="par92">
<LinkParameter id="par91" name="OID_dau2key [OID]" source="data.attN2F94A6"
target="dau2key.attN2F94A6" _sel="t"/>
<LinkParameter id="par92" name="name_KEYWORD" keyword="true" source="data.att10" _sel="t"/>
</layout:Link>
<Selector id="dau1sel" booleanOperator="and" _sel="t">
<KeyCondition id="dau1key" predicate="in" _sel="t"/>
</Selector>
<Link id="ln3" name="Combinations of this product" to="inu2" type="transport"
automaticCoupling="true" validate="true" _sel="t"/>
<Link id="ln9" name="To the Technical Record" to="dau6" type="transport" automaticCoupling="true"
validate="true" _sel="t"/>
<Link id="ln6" name="More images" to="dau2" type="normal" validate="true" gr:bendpoints=""
keywordOrder="par92" _sel="t">
<LinkParameter id="par91" name="OID_dau2key [OID]" source="data.attN2F94A6"
target="dau2key.attN2F94A6" _sel="t"/>
<LinkParameter id="par92" name="name_KEYWORD" keyword="true" source="data.att10" _sel="t"/>
</Link>
</layout:Unit>
The Layout XML contains all the static information about the unit, extracted from the Web Model (name, type, attributes, links, link parameters, etc.) and is interpreted by the template during generation, resulting in the final JSP page.
Groovy scriplets can access to the Layout XML and are compiled before the WR tags: in this way, one can define conditions influencing the evaluation of some parts of the template, or give a context to the WR tags. By using Groovy it is possible to decide whether a part of page is hidden or not, or which data has to be shown. In this example, in a Data Unit template, we separately print a single attribute "name":
#?delimiters [%, %], [%=, %]
<!--...-->
[%
import org.apache.commons.lang.math.NumberUtils
import org.apache.commons.lang.StringUtils
// parameter definition omitted
setHTMLOutput()
def unitId = unit["id"] // the implicit variable "unit" contains the Layout XML of the unit:
// in this way we have defined a variable containing the id of the unit
// define variable "name" containing a reference to the Layout XML
// of the attribute with name equal to "name"
def name = unit.selectSingleNode("layout:Attribute[@name='name']")
%]
[% if (useEmptyUnitMessage != "true") { //if the parameter is true, include the following code %]
<c:if test="${not(empty <wr:UnitId/>) and (<wr:UnitId/>.dataSize gt 0)}"> <!--JSTL tag evaluated at
runtime-->
[% } else { //if the parameter is not true, include the following code %]
<c:choose>
<c:when test="${not(empty <wr:UnitId/>) and (<wr:UnitId/>.dataSize gt 0)}">
[% } %]
<wr:Frame> <!--include the frame (if defined) for the unit-->
<div class="plain <wr:StyleClass/>"> <!-- Prints the name of the CSS style class -->
<div class="plain DataUnit">
<table>
<tr>
<td>
<wr:Value context="name"/> <!-- Prints separately the attribute "name" -->
</td>
</tr>
<wr:Iterate var="attr" context="unit" select="layout:Attribute[@name!='name']">
<!-- iterates over the attributes excluding "name" -->
<wr:Visible> <!-- Shows or hides its contents depending on the visibility -->
<tr>
<th valign="top" class="<wr:StyleClass/> header">
<wr:Label/> <!-- Prints the label of the attribute -->
</th>
<td valign="top" class="<wr:StyleClass/> value">
<wr:Value/> <!-- Prints the value of the attribute -->
</td>
</tr>
</wr:Visible>
</wr:Iterate>
<tr>
<td colspan="2">
<table>
<tr>
<wr:Iterate var="link" context="unit" select="layout:Link"> <!-- Iterates over the links -->
<wr:Visible>
<td><wr:Link class="link"/></td>
</wr:Visible>
</wr:Iterate>
</tr>
</table>
</td>
</tr>
</table>
</div>
</div>
</wr:Frame>
[% if (useEmptyUnitMessage != "true") { %]
</c:if>
[% } else { %]
</c:when>
<c:otherwise>
<wr:Frame>
<div class="plain <wr:StyleClass/>">
<div class="plain DataUnit">
<table>
<tr>
<td><bean:message key="[%printJSPTagValue(emptyUnitMessage)%]"/></td> <!-- uses a key to retrieve and display a localized message -->
</tr>
</table>
</div>
</div>
</wr:Frame>
</c:otherwise>
</c:choose>
[% } %]
In this example, a Groovy scriplet is used to select the attribute to be printed separately. The selectSingleNode method uses an XPath to search the Layout XML of the page for a single element. After that, it is possible to use the declared variable in the context attribute of a wr:Value tag to print its value.
Another way to refer to attributes is by their layout position. The selectNodes method uses an XPath to extract from the Layout XML a list of elements, that can be later accessed with Groovy. Here's an example:
[%
def firstAttribute = unit.selectNodes("layout:Attribute")[0] //first element of the list returned by
//the selectNodes method
def secondAttribute = unit.selectNodes("layout:Attribute")[1]
def thirdAttribute = unit.selectNodes("layout:Attribute")[2]
%]
Like before, it is possible to use the context attribute of the wr:Value or wr:Label tags to print the selected attributes in the template.
The bean object of units holding multiple data (e.g. Index Unit) uses lists to store multiple "rows" of attribute values, and therefore, a construct to iterate over the lists elements is required. This is done using the forEach JSTL tag that, at runtime, iterates over all the data rows, while the wr:Iterate is still responsible for iterating over attributes of each row.
As before, here's an example of an Index Unit template that prints separately the first and second attributes, followed by all the other attributes.
#?delimiters [%, %], [%=, %]
<!-- parameters definition omitted -->
[%
import org.apache.commons.lang.StringUtils
import org.apache.commons.lang.math.NumberUtils
setHTMLOutput()
def unitId = unit["id"]
def useEmptyUnitMessage = params["use-empty-unit-message"]
def emptyUnitMessage = params["empty-unit-message"]
def links = unit.selectNodes("layout:Link") // all the links of the unit
def unitLink = unit.selectSingleNode("layout:Link") // the first link of the unit
def link = unitLink?.valueOf("@link")
def firstAttribute = unit.selectSingleNode("layout:Attribute[1]") // first attribute in the layout
// XML, selected using
// selectSingleNode and XPath
def secondAttribute = unit.selectSingleNode("layout:Attribute[2]")
%]
[% if (useEmptyUnitMessage != "true") { %]
<c:if test="${not(empty <wr:UnitId/>) and (<wr:UnitId/>.dataSize gt 0)}">
[% } else { %]
<c:choose>
<c:when test="${not(empty <wr:UnitId/>) and (<wr:UnitId/>.dataSize gt 0)}">
[% } %]
<wr:Frame>
<div class="plain <wr:StyleClass/>">
<div class="plain IndexUnit">
<table border="0" cellspacing="1" cellpadding="2"
id="[%= unit["id"] + "_" + wr.ajaxUnits.indexOf(unit) + "_sortable" %]">
<tr>
[% if (links.size() == 1) {%]
<wr:Visible context="unitLink">
<th></th>
</wr:Visible>
[% } %]
<wr:Iterate var="l" context="unit" select="layout:Attribute[position() > 2]" >
<!-- iterates over all unit attributes with position greater than 2 in the
Unit Layout XML -->
<wr:Visible>
<th nowrap="nowrap" class="<wr:StyleClass/> header">
<wr:Label/>
</th>
</wr:Visible>
</wr:Iterate>
[% if (links.size() > 1) { %]
<wr:Iterate var="l" context="unit" select="layout:Link">
<!-- if the unit has more than one link, prints a th for each link -->
<wr:Visible>
<th></th>
</wr:Visible>
</wr:Iterate>
[% } %]
</tr>
<c:forEach var="current" varStatus="status" items="${<wr:UnitId/>.data}">
<c:set var="index" value="${status.index}"/>
<!-- iterates over the data field of the Index Unit bean (containing all the data rows) -->
<!--...-->
<tr>
<!-- iterate over attributes in current row with position greater than 2 -->
<wr:Iterate var="attr" context="unit" select="layout:Attribute[position() > 2]">
<wr:Visible>
<td class="<wr:StyleClass/> value
<c:if test="${<wr:UnitId/>.currentIndex eq index}">Current</c:if>">
<wr:Value/>
</td>
</wr:Visible>
</wr:Iterate>
<wr:Iterate var="l" context="unit" select="layout:Link">
<!-- iterate over all links departing from current row -->
<wr:Visible>
<td>
<c:choose>
<c:when test="${<wr:UnitId/>.currentIndex eq index}">
<wr:Link class="linkCurrent"/>
</c:when>
<c:otherwise>
<wr:Link class="link"/>
</c:otherwise>
</c:choose>
</td>
</wr:Visible>
</wr:Iterate>
</tr>
</c:forEach>
</table>
<table>
<c:forEach var="current" varStatus="status" items="${<wr:UnitId/>.data}">
<c:set var="index" value="${status.index}"/>
<!-- iterates again over bean's data to print the previosly selected attributes for each row -->
<tr>
<td><wr:Value context="firstAttribute"/></td> <!-- print the first attribute -->
<td><wr:Value context="secondAttribute"/></td> <!-- print the second attribute -->
</tr>
</c:forEach>
</table>
</div>
</div>
</wr:Frame>
<!--...-->
In this example, the XPath expression of wr:Iterate on attributes includes the "position" function: this function returns the relative 1-based position of a Layout XML element inside the iterated list.
| Related articles: |
