It is now possible to customize many aspects of JSP tag libraries using simple, powerful metadata files. Most notable is the ability to write Velocity HTML rendering templates to customize the rendering of JSP tags and JSF components in the JSP design editor.
This topic contains the following sections:
Workshop products integrate many of the standard tag libraries (HTML, JSP, JSTL, Struts, JSF etc). This integration allows the IDE to control things like:
This topic shows you how to customize the IDE for other JSP tag libraries and JSF components. Tag libraries customization is specified in an xml-format Tag Library Extra Information (tlei) file that should meet the following requirements:
For example, you might customize the tag library "/WEB-INF/app.tld" in the file "/WEB-INF/app.tlei" or "/WEB-INF/nitrox/app.tlei".
An example of a tlei file follows:
<tlei> <css-uri>app.css</css-uri> <tag name="myTag"> <display-name>My Tag</display-name> <small-icon>images/myTag.gif</small-icon> <!-- render the tag as 3 text fields separated by / --> <rendering-template><![CDATA[ <input type="text" name="month" size="2"/> / <input type="text" name="day" size="2"/> / <input type="text" name="year" size="4"/> ]]></rendering-template> <attribute name="myAttr"> <sub-type>uri</sub-type> </attribute> </tag> </tlei>
The following sections describe the various tlei tags.
Tag rendering controls how a tag is presented in the JSP editor's Design view. By default the editor renders a custom tag as a framed box containing the tag icon and name. Tag rendering can be customized in the tlei file as follows:
By default the design editor renders a
custom tag as a framed box containing the tag icon and the tag prefix:name as a
label. You can customize this label by using the
The rendering-label tag can contain any text mixed with any of the following special expressions which are evaluated dynamically:
${tag.name}: Replaced with the tag
name.
${tag.fullName}: Replaced with the tag prefix
and tag name (for example h:commandView ).
${tag.displayName}: Replaced with the tag
display name specified in the tlei file using the
display-name tag. If no display name is specified then the tag
name is used.
${tag.attr.attrName}: Replaced with
the attribute value of the attribute named attrName . For
example ${tag.attr.myAttr} . You could also specify a list
of attribute names separated by the '|' character. The first non-null
attribute value replaces the pattern. For example:
${tag.attr.action|name} would be replaced by the
action attribute value unless it is null, in which case it is
replaced by the name attribute value.
For example:
<tlei> <tag name="myTag"> <rendering-label>${tag.fullName} (${tag.attr.page})</rendering-label> </tag> </tlei>
You can specify a Velocity template to be used as the rendering JSP source code. In general, the template contains arbitrary HTML/JSP along with Velocity expressions for conditional/iterative content. You do not need extensive Velocity experience to write a rendering template, the examples in this section will show you many common cases. For more advanced Velocity usage consult the Velocity User Guide. Note that the template does not necessarily need to have Velocity expressions. For example if the tag represents a date, and you want it to be rendered as 3 edit fields regardless, then you can specify it as follows:
<tlei> <tag name="myTag"> <rendering-template><![CDATA[ <input type="text" name="month" size="2"/> / <input type="text" name="day" size="2"/> / <input type="text" name="year" size="4"/> ]]></rendering-template> </tag> </tlei>Note that the template content should to be enclosed in
${tag.name}: Evaluates to the tag name. For
example: <tlei>
<tag name="myTag">
<rendering-template><![CDATA[
<span style="color: red">${tag.name}</span>
]]></rendering-template>
</tag>
</tlei>
renders as the tag name in red.
${tag.fullName}: Evaluates to the tag prefix
and tag name (for example h:commandView ).
${tag.displayName} : Evaluates to
the tag display name specified in the tlei file using the
display-name tag. If no display name is specified then the tag
name is used.
${tag.missingAttr("attrName")}: A
boolean expression evaluating to true if the tag does not have the given
attribute.
${tag.attr("attrName")}: Evaluates to
the attribute value of the attribute named attrName .
Evaluates to an empty string if the tag does not have the given
attribute. For example: <tlei>
<tag name="myTag">
<rendering-template><![CDATA[
#if (!$tag.missingAttr("attr1"))
${tag.attr("attr1")}
#else
${tag.attr("attr2")}
#end
]]></rendering-template>
</tag>
</tlei>
renders the value of the attribute attr1
unless it is not specified in the tag where it renders the value of the
attribute attr2 .
${tag.attrInt("attrName")}: Same as
${tag.attr("attrName")} but converts the value to an
integer. Evaluates to 0 if the tag does not have the given attribute, or if
the value cannot be converted to integer. This could be used in some cases
to generate iterative content based on a tag attribute value.
${tag.empty}: A boolean expression evaluating
to true if the tag does not have any children (i.e no body content).
${tag.childrenTags}: Evaluates to the list of
children tags, empty list if none. You would usually iterate the returned
list and use the iteration variable as a tag variable. For example: <tlei>
<tag name="myTag">
<rendering-template><![CDATA[
#set ($count = 0)
#foreach ($childTag in $tag.childrenTags)
#if (${childTag.name} == "myOtherTag")
#set ($count = $count + 1)
#end
#end
Found ${count} myOtherTag tags.
]]></rendering-template>
</tag>
</tlei>
renders the count of children tags having a
specific name.
${tag.childrenSource}: Evaluates to the JSP
source code of the tag's children, or empty string if none (i.e if the tag
does not have any children). For example, a tree node tag could be rendered
as follows: <tlei>
<tag name="myTag">
<rendering-template><![CDATA[
${tag.attr("label")}
#if (!${tag.empty})
<div style="margin-left: 30">${tag.childrenSource}</div>
#end
]]></rendering-template>
</tag>
</tlei>
It renders the node label, then renders the children nodes
(if any) indented. Note that in this example, nested children tree nodes
tags are rendered recursively using the same markup templates!
${tag.childTag(name, prefix,
attrName, attrValue)}: Evaluates to the first child
tag matching the given tag name, tag prefix and attribute name/value. For
example: <tlei>
<tag name="myTag">
<rendering-template><![CDATA[
#set ($header = $tag.childTag("facet", "f", "name", "header"))
#if ($header) Found header facet: ${header.childrenSource}
#else Header facet not found!
#end
]]></rendering-template>
</tag>
</tlei>
renders the content of the nested f:facet tag
having a name equals to header , or an error message
if not found.
${tag.childTag(name,
prefix)}: Evaluates to the first child tag matching the given
tag name and tag prefix (regardless of any attribute value).
${tag.url("uri")}: Evaluates to the
absolute url corresponding to the given relative uri. The uri should be
relative to the location of the file containing the template (i.e relative to
the tlei file if you are using the rendering-template tag, or
relative to the template file if you are using the
rendering-template -uri tag as described later). Usually you
use the url function if your template contains images to compute the image
source so that the editor can find them. For example: <tlei>
<tag name="myTag">
<rendering-template><![CDATA[
<img src="${tag.url("images/myImage.gif")}"/>
<input type="text" name="" size="20"/> ]]></rendering-template>
</tag>
</tlei>
renders an image and a text input field. Note that in this
example the image myImage.gif should be located in a folder named
images which should be present in the same directory as the tlei file
(where the template is specified).
${tag.icon}: Evaluates to the absolute url of
the tag icon specified in the tlei file using the small-icon tag.
You can specify a rendering template in its own file using the rendering-template-uri tag. This is usually used if the rendering template is shared between multiple tags, or if it is large. The template file should be specified relative to the location of the tlei file. It could have any name and any file extension. For example:
<tlei> <tag name="myTag"> <rendering-template-uri>templates/myTag.vm</rendering-template-uri> </tag> </tlei>
Note that in this example the file myTag.vm should be located in a
folder named templates which should be present in the same directory
as the tlei file. Of course when you use a separate template file the
Following are examples of how the IDE uses the rendering templates for some of the MyFaces JSF components:
x:commandNavigation
<a href="#">${tag.attr("value")}</a> #if (!$tag.empty) <div style="margin-left: 16">${tag.childrenSource}</div> #end
x:inputDate
#set ($type = ${tag.attr("type")}) #set ($styleClass = ${tag.attr("styleClass")}) #set ($style = ${tag.attr("style")}) #if (!($type == "time"))
<input type="text" name="day" size="8" class="$styleClass" style="$style"/> <select name="month" class="$styleClass" style="$style"/> <input type="text" name="year" size="10" class="$styleClass" style="$style"/> #if (${tag.attr("popupCalendar")} == "true") <input type="button" value="..."/> #end #end
#if ($type == "both" || $type == "time")
<input type="text" name="hour" size="10" class="$styleClass" style="$style"/> :<input type="text" name="minute" size="10" class="$styleClass" style="$style"/> :<input type="text" name="second" size="10" class="$styleClass" style="$style"/>
#end
x:dataScroller
#if (${tag.attr("renderAsPopup")} == "true")
<input type="text" name="${tag.attr("value")}" class="${tag.attr("styleClass")}" style="${tag.attr("style")}"/> <input type="button" value="..."/>
#else
<table class="${tag.attr("styleClass")}" style="${tag.attr("style")}>
<tr class="${tag.attr("monthYearRowClass")}">
<td><a href="#"><</a></td>
<td colspan="5">Month Year</td>
<td><a href="#">></a></td>
</tr> <tr class="${tag.attr("weekRowClass")}">
<td>Sun</td>
<td>Mon</td>
<td>Tue</td>
<td>Wed</td>
<td>Thu</td>
<td>Fri</td>
<td>Sat</td>
</tr> #foreach ($i in [0..4])
<tr>
#foreach ($j in [0..6])
#set ($day = $i * 7 + $j)
#if ($day <= 0)
<td class="${tag.attr("dayCellClass")}"></td>
#elseif ($day == 7)
<td class="${tag.attr("currentDayCellClass")}"><a href="#">$day</a></td>
#elseif ($day <= 31)
<td class="${tag.attr("dayCellClass")}"><a href="#">$day</a></td>
#end
#end
</tr>
#end
</table>
#end
x:dataScroller
#macro (facet $facetName)
#if ($tag.childTag("facet", "f", "name", $facetName))
<td>
#set ($facetTag = $tag.childTag("facet", "f", "name", $facetName))
<a href="#">$facetTag.childrenSource</a>
</td>
#end
#end <table><tr>
#facet("first")
#facet("fastrewind")
#facet("previous") #if ($tag.attr("paginator") == "true")
<td> <table cellpadding="1" cellspacing="1" class="${tag.attr("paginatorTableClass")}" style="${tag.attr("paginatorTableStyle")}"><tr>
#set ($max = $tag.attrInt("paginatorMaxPages"))
#if ($max < 2)
#set ($max = 2)
#end
<td class="${tag.attr("paginatorActiveColumnClass")}" style="${tag.attr("paginatorActiveColumnStyle")}">
<a href="#">1</a>
</td>
#foreach ($i in [2..$max])
<td class="${tag.attr("paginatorColumnClass")}" style="${tag.attr("paginatorColumnStyle")}">
<a href="#">$i</a>
</td>
#end
</tr></table> </td>
#end #facet("next")
#facet("fastforward")
#facet("last")
</tr></table> #foreach ($child in $tag.childrenTags)
#if (!($child.name == "facet"))
$child.source
#end
#end
You can associate standard css styles to any of
the tag library tags. The css styles are declared in a css file specified using
the tlei tag
<tlei> <css-uri>app.css</css-uri> </tlei>Then add the line:
Tag attributes can be customized in the tlei file by specifying sub types and enumerations. There are 2 tlei tags for attribute customization:
<tlei> <tag name="myTag"> <attribute name="myAttr"> <enumeration>value1, value2</enumeration> </attribute> </tag> </tlei>This example associates an enumeration to the attribute myAttr of the tag myTag.
<tlei> <global-attribute name="action"> <sub-type>jsf-action</sub-type> </global-attribute> </tlei>Says that an attribute named action in any tag in the tag library should have the jsf-action sub type. This is just a shortcut of using the
The IDE predefines attribute sub types that makes it smarter when dealing with the attribute values in the areas of attribute value editing, attribute value navigation, page validation and consistency checking, and AppXRay dependencies. For example, by specifying the struts-action-mapping sub type for an attribute, the IDE would automatically:
Following are the predefined sub types along with the description of their corresponding attribute values:
You can specify that an attribute
value is limited to a predefined set of values by using the
<tlei> <tag name="myTag"> <attribute name="myAttr"> <enumeration>value1, value2</enumeration> </attribute> </tag> </tlei>
The IDE would automatically:
When a custom tag is edited in the design or source editors, the IDE by default shows a standard property sheet that allows modifying the tag attribute values. In many cases, especially for richer JSF components, the number of attributes is large and one would want to have a more optimized way to edit the "frequently used" attributes. You can do just that by defining a custom tag editor. Using metadata you specify what attributes to be shown and how they are grouped. The metadata is then used to present in the dialog-like Smart Editor ui along with the property sheet. In general, the tag editing dialog consists of editors for the attributes you specify in the metadata file. Each attribute editor consists of its editing control (a text field, combobox etc) along with a custom editing button added based on the attribute sub type if any (as described in the Tag Attributes section).
The tag editing metadata is specified in a
<tlei> <tag name="myTag"> <tag-edit-uri>tagedit/myTag.tagedit</tag-edit-uri> </tag> </tlei>
An example of a .tagedit file follows:
<tag-edit> <dialog-info kind="insert-modify"> <field-group> <field name="value"> <display-name>Value</display-name> <bind-info source-kind="any"/> </field> <field name="converter"> <display-name>Converter</display-name> </field> </field-group> <field-group> <label>CSS Properties</label> <field name="styleClass"> <display-name>CSS Class</display-name> </field> <field name="style"> <display-name>CSS Style</display-name> </field> </field-group> </dialog-info> </tag-edit>
Here are the description of the main tags:
You can have multiple dialog-info tags with different
You can control how a tag is formatted in the source code using the
For example:
<tlei> <tag name="myTag"> <format line-break="before-after" content-format="wrap-indent"/> </tag> </tlei>
Both the
The possible values for the
The possible values for the
The following tlei tags can be used to customize how the tags are presented in the Design Palette View:
For example:
<tlei> <display-name>My Tag Library</display-name> <description>The description of the tag library.</description> <tag name="myTag"> <display-name>My Tag</display-name> <description>The description of my tag.</description> <small-icon>images/myTag.gif</small-icon> </tag> </tlei>
Knowing that a tag library contains JSF components is very useful, for example, when deciding whether to enable JSF expressions and method binding for the attribute values.
You can specify that a tag library contains JSF
components by using the
<tlei> <property name="jsf" value="true"/> </tlei>