JBoss.orgCommunity Documentation
Thus, JSF components consist of two parts: the component class and the renderer. The component class is responsible for the state and behavior of a UI component and will be discussed later in the "Configuring component" section.
The Renderer is responsible for the JSF component representation. It generates the
appropriate client-side markup, such as HTML, WML, XUL, etc. Renderer is also
responsible for the converting information coming from the client to the proper type
for the component (for example, a string value from the request is converted to a
strongly type Date
object).
It is necessary to create following renderer classes for the <inputDate> component:
InputDateRenderer
class where you should override encode()
methods for encoding the markup and resources
InputDateRendererBase
class where you should override decode()
method.
You could also define associated converter in this class.
You could actually implement the renderer-specific component subclass that
exposes client-side attributes such as
"style"
,
"class"
, etc. It is common practice to implement the client-specific component
subclass to make some aspects of application development easier, but in our case we
do not need to do it. The
<inputDate>
is a simple UIInput
component, therefore
InputDateRenderer
class generates all the markup itself.
It is a time to start creating the InputDateRenderer
class.
The smartest way to create the InputDateRenderer
class is a Templating mechanism,
one of the most convenient features of the Component Development Kit (CDK).
The Component Development Kit (CDK) allows to use templates for generation Renderer class.
<?xml version="1.0" encoding="UTF-8"?>
<f:root
xmlns:f="http://ajax4jsf.org/cdk/template"
xmlns:c=" http://java.sun.com/jsf/core"
xmlns:ui=" http://ajax4jsf.org/cdk/ui"
xmlns:u=" http://ajax4jsf.org/cdk/u"
xmlns:x=" http://ajax4jsf.org/cdk/x"
class="org.mycompany.renderkit.html.InputDateRenderer"
baseclass="org.ajax4jsf.renderkit.AjaxComponentRendererBase"
component="org.mycompany.component.UIInputDate"
>
<f:clientid var="clientId"/>
<div id="#{clientId}"
x:passThruWithExclusions="value,name,type,id"
>
</div>
</f:root>
According to the created UI prototype you need to extend Template Skeleton with proper elements:
<div>-wrapper element with "title", "id" attributes and with the "caption" facet
...
<div id="#{clientId}" title="#{value}" x:passThruWithExclusions="value,name,type,id">
...
</div>
...
...
<input id="#{clientId}"
name="#{clientId}"
type="text"
value="#{this:getValueAsString(context, component)}"
class="my-inputDate-input #{component.attributes['inputClass']}"
style="#{component.attributes['inputStyle']}"/>
...
...
<f:resource name="/org/mycompany/renderkit/html/images/inputDate.png" var="icon" />
...
<img src="#{icon}" class="my-inputDate-icon #{component.attributes['iconClass']}" style="#{component.attributes['iconStyle']}"/>
...
...
<h:styles>/org/mycompany/renderkit/html/css/inputDate.xcss</h:styles>
...
How to register all resources is explained in the "Component resources registration" chapter.
Don't forget to add namespace xmlns:h=" http://ajax4jsf.org/cdk/h"
to the
<f:root> element:
<?xml version="1.0" encoding="UTF-8"?>
<f:root
...
xmlns:h=" http://ajax4jsf.org/cdk/h"
...
>
...
</f:root>
Here is a full example of the template for the <inputDate> component: htmlInputDate.jspx.
As it is seen in the Template Skeleton the Renderer Baseclass is org.ajax4jsf.renderkit.AjaxComponentRendererBase
.
You need to define Renderer Base class special for the <inputDate> component.
In the next section "Creating a Renderer Base class"
we will create Renderer Base class org.mycompany.renderkit.InputDateRendererBase
.
All the Template tags you could find in the "Template tags overview" chapter.
package org.mycompany.renderkit;
import java.io.IOException;
import java.util.Map;
import java.util.TimeZone;
import javax.faces.component.UIComponent;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.convert.DateTimeConverter;
import org.ajax4jsf.renderkit.HeaderResourcesRendererBase;
import org.mycompany.component.UIInputDate;
public abstract class InputDateRendererBase extends HeaderResourcesRendererBase {
...
}
...
public void decode(FacesContext context, UIComponent component){
ExternalContext external = context.getExternalContext();
Map requestParams = external.getRequestParameterMap();
UIInputDate inputDate = (UIInputDate)component;
String clientId = inputDate.getClientId(context);
String submittedValue = (String)requestParams.get(clientId);
if (submittedValue != null) {
inputDate.setSubmittedValue(submittedValue);
}
}
...
...
private Converter getConverter(FacesContext context, UIInputDate inputDate){
Converter converter = inputDate.getConverter();
if (converter == null){
// default the converter
DateTimeConverter datetime = new DateTimeConverter();
datetime.setLocale(context.getViewRoot().getLocale());
datetime.setTimeZone(TimeZone.getDefault());
datetime.setType("date");
datetime.setDateStyle("medium");
datetime.setPattern("d/m/y");
converter = datetime;
}
return converter;
}
...
...
public Object getConvertedValue(FacesContext context, UIComponent component, Object submittedValue) throws ConverterException{
UIInputDate inputDate = (UIInputDate)component;
Converter converter = getConverter(context, inputDate);
String valueString = (String)submittedValue;
return converter.getAsObject(context, component, valueString);
}
...
...
protected String getValueAsString(FacesContext context, UIComponent component) throws IOException {
UIInputDate inputDate = (UIInputDate) component;
String valueString = (String) inputDate.getSubmittedValue();
if (valueString == null) {
Object value = inputDate.getValue();
if (value != null) {
Converter converter = getConverter(context, inputDate);
valueString = converter.getAsString(context, component, value);
}
}
return valueString;
}
...
You could find the whole example of the InputDateRendererBase
class inInputDateRendererBase.java file.
One of the significant features of the Component Development Kit (CDK) is a skins-based technology which helps you to create a modern rich user interface look-and-feel. RichFaces has a number of predefined skins you could use with the <inputDate> component. But if you want to create your own skin, please, read carefully the "Skinnability" section of the RichFaces Developer Guide. You could find all necessary information about Built-in skinnability in RichFaces, XCSS file format, Plug-n-Skin feature, etc. there.
It's time to create XCSS file. You should go to the src/main/resources/org/mycompany/renderkit/html/css and create inputDate.xcss file there with the following skeleton:
<?xml version="1.0" encoding="UTF-8"?>
<f:template xmlns:f='http:/jsf.exadel.com/template'
xmlns:u='http:/jsf.exadel.com/template/util'
xmlns="http://www.w3.org/1999/xhtml">
...
</f:template>
According to the <inputDate> markup you need to define following selectors and classes in the inputDate.xcss:
.my-inputDate-input
, .my-inputDate-icon
selectors
...
<u:selector name=".my-inputDate-input">
<u:style name="border-color" skin="panelBorderColor"/>
<u:style name="background-color" skin="controlBackgroundColor"/>
<u:style name="color" skin="controlTextColor"/>
<u:style name="font-family" skin="generalFamilyFont"/>
<u:style name="font-size" skin="generalSizeFont"/>
</u:selector>
<u:selector name=".my-inputDate-icon">
<u:style name="border-color" skin="panelBorderColor"/>
<u:style name="background-image">
<f:resource f:key="/org/mycompany/renderkit/html/images/inputDate.png" />
</u:style>
</u:selector>
...
.my-inputDate-input
, .my-inputDate-icon
, and .my-inputDate-caption
classes
...
.my-inputDate-input{
background-color: #EBEBE4;
border: 1px solid #7F9DB9;
float:left;
}
.my-inputDate-icon{
margin-left: 3px;
}
.my-inputDate-caption{
color: #000000;
}
...
You could find a complete inputDate.xcss in inputDate.xcss file.