Struts 2 > Themes |

Struts 2
Themes
Edit Page Browse Space Add Page Add News
Added by casey, last edited by Ted Husted on Sep 03, 2006 (view change)

A Theme is a set of Templates used to customize web page development with UI tags. They provide a powerful mechanism to help web developers spice up the UI with a mixture of styles (colors, fonts, etc). For example, you may want half your form textfields to have a blue background and half a white background. A couple of notes:

- Webwork comes with 2 pre-defined themes; "simple" and "xhtml" (default). The default location webwork looks for themes in your web application is `/template`. The default theme is `xhtml`. Default, meaning that it will be used if you don't specify a theme attribute in your UI tag. Note: The default values can be overridden in your struts.properties file with `webwork.ui.theme=` and `webwork.ui.templateDir=`.

- Custom themes can also be created to tailor your own needs. We recommend you consult the pre-defined templates as a starting point before you create your own.

- Every time a UI tag is used, the tag is rendered into html by referencing a template. So they play a key role in how fields look and are positioned in a page. Currently, only velocity templates are supported out of the box. However, expect to see more support for creating JSP templates in future releases.

Note: Before moving forward, it is recommended that you review how the webwork template system works. (see Templates)

### xhtml

`xhtml` comes configured as the default theme for Webwork. It extends the simple theme providing built in functionality for error reporting, table positioning, and labeling. Lets look at one of the most common UI tags used, `textfield`, and show the proper way to write your views with the xhtml theme.

As you may already know, the default UI template used for the textfield tag is text.vm located under the directory /template/xhtml.

    #*
       -- text.vm
    *#
    ## notice the re-use of the simple theme template text.vm
    #parse("/template/xhtml/controlheader.vm")
    #parse("/template/simple/text.vm")
    #parse("/template/xhtml/controlfooter.vm")

When this template is loaded, it will first parse and render the /template/xhtml/controlheader.vm. Within controlheader.vm you will notice functionlity for error reporting, labeling and table positioning. If ActionSupport is returning with some errors, they are rendered into html using this this template. Also you will notice how it grabs the parameter.label value and positions it with the textfield using the table elements tr and td.

    #*
       -- controlheader.vm
    *#
    ## Only show message if errors are available.
    ## This will be done if ActionSupport is used.

    #if( $fieldErrors.get($parameters.name) )
      #set ($hasFieldErrors = $fieldErrors.get($parameters.name))
      #foreach ($error in $fieldErrors.get($parameters.name))
        <tr>
            #if ($parameters.labelposition == 'top')
                <td align="left" valign="top" colspan="2">
            #else
                <td align="center" valign="top" colspan="2">
            #end
                <span class="errorMessage">$!webwork.htmlEncode($error)</span>
                </td>
        </tr>
      #end
    #end

    ## Provides alignment behavior with table tags
    ## if the label position is top,
    ## then give the label it's own row in the table
    ## otherwise, display the label to the left on same row

    <tr>
        #if ($parameters.labelposition == 'top')
            <td align="left" valign="top" colspan="2">
        #else
            <td align="right" valign="top">
        #end

            #if ($hasFieldErrors)
                <span class="errorLabel">
            #else
                <span class="label">
            #end

    ## If you want to mark required form fields with an asterisk,
    ## you can set the required attribute
    ## Ex. <ui:textfield label="'mylabel'" name="'myname'" required="'true'" />
            #if ($parameters.label)
                #if ($parameters.required) <span class="required">*</span> #end
                   $!webwork.htmlEncode($parameters.label):
            #end
                </span>
            </td>

    ## add the extra row
    #if ($parameters.labelposition == 'top')
    </tr>
    <tr>
    #end
        <td>

The next template being parsed in /template/xhtml/text.vm is /template/simple/text.vm. Here you see the actual html input text tag being rendered and how the parameters are passed in.

    #*
      -- text.vm
      --
      -- Required Parameters:
      --   * label      - The description that will be used to identfy the control.
      --   * name       - The name of the attribute to put and pull the result from.
      --                  Equates to the NAME parameter of the HTML INPUT tag.
      --
      -- Optional Parameters:
      --   * labelposition   - determines were the label will be place in relation
      --                       to the control.  Default is to the left of the control.
      --   * size       - SIZE parameter of the HTML INPUT tag.
      --   * maxlength  - MAXLENGTH parameter of the HTML INPUT tag.
      --   * disabled   - DISABLED parameter of the HTML INPUT tag.
      --   * readonly   - READONLY parameter of the HTML INPUT tag.
      --   * onkeyup    - onkeyup parameter of the HTML INPUT tag.
      --   * tabindex  - tabindex parameter of the HTML INPUT tag.
      --   * onchange  - onkeyup parameter of the HTML INPUT tag.
      --
        *#
    <input type="text"
                                       name="$!webwork.htmlEncode($parameters.name)"
    #if ($parameters.size)             size="$!webwork.htmlEncode($parameters.size)"            #end
    #if ($parameters.maxlength)        maxlength="$!webwork.htmlEncode($parameters.maxlength)"  #end
    #if ($parameters.nameValue)        value="$!webwork.htmlEncode($parameters.nameValue)"      #end
    #if ($parameters.disabled == true) disabled="disabled"                                      #end
    #if ($parameters.readonly)         readonly="readonly"                                      #end
    #if ($parameters.onkeyup)          onkeyup="$!webwork.htmlEncode($parameters.onkeyup)"      #end
    #if ($parameters.tabindex)         tabindex="$!webwork.htmlEncode($parameters.tabindex)"    #end
    #if ($parameters.onchange)         onchange="$!webwork.htmlEncode($parameters.onchange)"    #end
    #if ($parameters.id)               id="$!webwork.htmlEncode($parameters.id)"                #end
    #if ($parameters.cssClass)         class="$!webwork.htmlEncode($parameters.cssClass)"       #end
    #if ($parameters.cssStyle)         style="$!webwork.htmlEncode($parameters.cssStyle)"       #end
    />

And finally, the controlfooter.vm is parsed to close up the td and tr tags that were previously opened in controlheader.vm

    #*
       -- controlheader.vm
    *#

      </td>
    </tr>

In our view, since the tr and td elements are already created for us, we can simply wrap them with table elements. For the sake of learning, we will just use normal html table objects, but feel free to look into how the table.vm tag gets rendered and possibly use that.

    <%@ taglib uri="webwork" prefix="ui" %>
    <link rel ="stylesheet" type="text/css" href="template/xhtml/styles.css" title="Style">
    <html>
    <head><title>JSP PAGE</title></head>
    <body>
    <form>
      <table>
    	<!-- we can set the required attribute to true if we want to
    	     display and asterisk next to required form fields
    	 -->

    	<ui:textfield label="'Username'" required="'true'" name="'user'" />
    	<ui:textfield label="'Email'" name="'email'"/>
      </table>
    </form>
    </body>
    </html>

    <link rel ="stylesheet" type="text/css" href="template/xhtml/styles.css" title="Style">
    <html>
    <head><title>VM PAGE</title></head>
    <body>
    <form>
      <table>
        #tag( TextField "label='Username'" "name='user'" )<br>
        #tag( TextField "label='Email'" "name='email'" )<br>
      </table>
    </form>
    </body>
    </html>

### css_xhtml

The css_xhtml theme is a theme based entirely on css and thus avoids the dependency on tables.
Lets review the code to see how this theme works.

Generated HTML code

    <div>
    <p>
    <label for="frm1_caseBean.title" class="label"><span class="required">*</span>Title:</label>
    <input name="caseBean.title" size="70" id="frm1__caseBean.title" onblur="validate(this);" type="text">
    </p>
    </div>

The first thing of note is the containing DIV tag. This is the container element that will be filled with Field Validation errors. The second element is the P, this is a block element and will thusly but both the lable and the control on its own line. notice how we use the 'for' attribute of the label tag? That helps to identify that this label is for a control. This feature is uber cool for checkboxes as it extends the clickable range of the checkbox to the label as well!!!

You might also have noticed the CSS class attributes... lets review these:

    .label {
        font-style:italic;
        float:left;
        width:30%
    }
    .errorLabel {font-style:italic; color:red; }
    .errorMessage {font-weight:bold; text-align: center; color:red; }
    .checkboxLabel {}
    .checkboxErrorLabel {color:red; }
    .required {color:red;}

This style sheet is included in the WW2.2 packaging. All you need to do to take advantage of it is include this line in your header:
<link href="<%=request.getContextPath()%>/webwork/template/css_xhtml/styles.css" rel="stylesheet" type="text/css">

If you want to customize any attribute of these CSS rules.. just put your deltas into your own css file and include it AFTER the above css include.

Some interesting things about the theme are how it supports both standard validation and DWR validation. Lets review the structure of some generated code to understand how the css_xhtml theme does validation.

    <div>

    <p>

    <div errorfor="frm1_bo.emailAddress" classname="errorMessage" class="errorMessage">Incorrect Email</div><label classname="errorLabel" for="frm1_bo.emailAddress" class="errorLabel"><span class="required">*</span>Email:</label>

    <input name="bo.emailAddress" size="20" value="not_yet_d@efined.com" id="frm1_bo.emailAddress" onblur="validate(this);" type="text">
    </p>
    </div>

The validation gets inserted into the structure for you by either the validation.js script if your using the DWR Client Side validator or server side template if your using standard validation.

| No Orientation Support Some themes support label orientation... ie:either top or bottom... this theme does not.

### simple

The `simple` theme provides no additional functionality from HTML tags (similiar to struts). This theme is considered the low end of the structure and can be re-used (extended) like xhtml to add additional functionality or behavior. You can easily create your own theme and extend this one to create complex pages that fit your own needs.
To use the pre-defined theme `simple`

    <%@ taglib uri="webwork" prefix="ui" %>
    <link rel ="stylesheet" type="text/css" href="template/xhtml/styles.css" title="Style">
    <html>
    <head><title>JSP PAGE</title></head>
    <body>
      <form>
    	<ui:label name="'userlabel'" label="'user" theme="'simple'"/>
                    <ui:textfield name="'user'" theme="'simple'"/>

    	<ui:label name="'emaillabel'" label="'user" theme="'simple'"/>
                    <ui:textfield name="'email'" theme="'simple'"/>
      </form>
    </body>
    </html>

    <link rel ="stylesheet" type="text/css" href="template/xhtml/styles.css" title="Style">
    <html>
    <head><title>VM PAGE</title></head>
    <body>
      <form>
    #tag( Label  "name='userlabel'" "label='user'" "theme='simple'" )
    #tag( TextField  "name='user'" "theme='simple'" )<br>

    #tag( Label  "name='emaillabel'" "label='email'" "theme='simple'" )
    #tag( TextField  "name='email'" "theme='simple'" )<br>
      </form>
    </body>
    </html>

### Creating your own theme

Creating themes is quite simple and can save valuable time enabling you to minimize UI code when it comes to creating complex UI pages. It is recommended you understand webwork templates before you continue (see Templates). The steps required to use a theme.

1. Define a name for your theme by creating a subdirectory under /template directory. The name of the subdirectory you create will be the same as the value you specify in your UI tag theme attribute.

       /template/myTheme

       <ui:textfield label="'foo'" name="'bar'" theme="'myTheme'" />

2. Create a velocity template for every UI tag that you want to use with your theme. For example, if you have forms with only textfields and nothing else, then all you need in your subdirectory is a text.vm template. Note: if you create a text.vm and reference another template with the parse tag, then you must make sure these templates are defined as well(ex. controlheader.vm).
3. If you want your new theme to be the default so you don't have to specify the theme attribute every time in the UI tag, then modify the webwork.ui.theme value in your webwork.properties file. Otherwise, you can just specify the theme attribute in all your UI tags.

As a good starting point, a good idea is to copy the contents of xhtml into a new subdirectory. Therefore, you can modify the templates and still refer back to the originals as a reference point.