Starting
with JSF 2.2 we have more control on writing custom themes for JSF. In order to
write a basic theme, you have to know a few things, as follows:
1.
Themes are known in JSF as contracts
2.
Contracts are placed in a folder named, contracts under the Web root
of the application, or under the META-INF folder that resides in a JAR file
3.
We can alter the location and the name of this
folder via WEBAPP_CONTRACTS_DIRECTORY_PARAM_NAME
context parameter in web.xml
4.
Commonly, under the contracts folder, we define a
subfolder for each contract
5.
The subfolder's name represents the contract's
name
6.
A contract contains the contract's artifacts
such as the CSS, JS, images, and XHTML templates
If we follow
a simple <ui:insert>
- <ui:define>
construction:
<!-- in template file -->
<ui:insert
name="content"/>
<!-- in page that uses the
template -->
<ui:define
name="content">
...
</ui:define>
Then we can
simply isolate the CSS classes from below - basically, we style the HTML
rendered by JSF:
.content {} /* main div */
.content div {} /*
<h:panelGroup> */
.content table {} /*
<h:dataTable>, <h:panelGrid> *>
.content table td,.content table th
{}
.content table thead th {}
.content table thead th:first-child
{}
.content table tbody td {}
.content table tbody .alt td {}
.content table tbody td:first-child
{}
.content table tbody tr:last-child
td {}
.content table tfoot td div {}
.content table tfoot td {}
.content table tfoot td ul {}
.content table tfoot li {}
.content table tfoot li a {}
.content table tfoot
ul.active,.content table tfoot ul a:hover {}
.content input[type=text] {} /* <h:inputText> */
.content input[type=password] {} /* <h:inputsecret> */
.content input[type=submit] {} /* <h:commandButton> */
.content textarea {} /*
<h:inputTextarea> */
.content label {} /*
<h:outputLabel> */
.content select {} /*
<h:selectOneMenu>,
<h:selectOneListbox>,
<h:selectManyMenu>,
<h:selectManyListbox>
*/
.content input[type=radio] {} /* <h:selectOneRadio> */
.content input[type=checkbox] {} /* <h:selectManyCheckbox>
*/
.content input:hover {}
.content input:active {}
.content input[type=radio] + label
{}
.content input[type=radio]:checked
+ label {}
.content input[type=checkbox] +
label {}
.content
input[type=checkbox]:checked + label {}
You
can easily add CSS classes for the rest of UI components.
Now, you can
provide your custom CSS code and obtain a basic JSF theme.
Per example,
let's see the output of a JSF page without using CSS code (of course, you can use some CSS snippets to align things and provide a decent look, but we want a theme component's width and/or height):
The code behind this screenshot is listed below (notice that there is no CSS inline/defined in code below, but you can do it if you need to override someting from the theme (e.g.components width and/or height):
<h:panelGrid
columns="4">
<f:facet
name="header">
<h:graphicImage
library="default" name="images/rafa.png"/>
</f:facet>
<h:form
enctype="multipart/form-data">
<h:panelGrid
columns="2">
<f:facet
name="header">
Upload
photos with first three ATP players
</f:facet>
<h:outputLabel for="fileToUploadId" value="Select
photos:"/>
<h:inputFile
id="fileToUploadId" value=""/>
<h:outputLabel
for="playerPhotoId" value="Players names:"/>
<h:selectManyListbox id="playerPhotoId"
value="">
<f:selectItem itemValue="RN" itemLabel="RAFAEL NADAL"
/>
<f:selectItem itemValue="RF" itemLabel="NOVAK
DJOKOVIC" />
<f:selectItem itemValue="NJ" itemLabel="DAVID
FERRER" />
</h:selectManyListbox>
<h:outputLabel for="selectId" value="Convert
to:"/>
<h:selectOneMenu id="selectId" value="">
<f:selectItem itemValue="PNG" itemLabel="Portable
Network Graphics (PNG)" />
<f:selectItem itemValue="JPG" itemLabel="Joint
Photographic Experts Group (JPG)" />
<f:selectItem
itemValue="BMP" itemLabel="Bitmap (BMP)" />
</h:selectOneMenu>
</h:panelGrid>
</h:form>
<h:form>
<h:panelGrid
columns="1">
<f:facet
name="header">
Download
your photos
</f:facet>
<h:outputLabel for="sizeId" value="Select
size:"/>
<h:panelGroup id="downloadDivId"
layout="block">
<h:selectOneRadio id="sizeId" value="">
<f:selectItem itemValue="16x16" itemLabel="16x16"
/>
<f:selectItem
itemValue="250x250" itemLabel="250x250" />
<f:selectItem itemValue="1280x720"
itemLabel="1280x720" />
</h:selectOneRadio>
</h:panelGroup>
<h:commandButton value="Download"/>
</h:panelGrid>
</h:form>
<h:form>
<h:panelGrid
columns="2">
<f:facet
name="header">
Log in
</f:facet>
<h:outputLabel for="emailId" value="E-mail:"/>
<h:inputText
value=""/>
<h:outputLabel for="passwordId"
value="Password:"/>
<h:inputSecret value=""/>
</h:panelGrid>
</h:form>
<h:form>
<h:panelGrid
columns="2">
<f:facet
name="header">
Contact Us
</f:facet>
<h:outputLabel for="subjectId"
value="Subject:"/>
<h:inputText
id="subjectId" value=""/>
<h:outputLabel for="messId" value="Message:"/>
<h:inputTextarea
id="messId" cols="100"/>
<f:verbatim/>
<h:commandButton value="Send"/>
</h:panelGrid>
</h:form>
</h:panelGrid>
<h:panelGrid
columns="1">
<f:facet
name="header">
ATP Singles Today
</f:facet>
<h:dataTable
value="#{playersBean.data}" var="t"
border="1">
<h:column>
<f:facet
name="header">
Ranking
</f:facet>
#{t.ranking}
</h:column>
<h:column>
<f:facet
name="header">
Name
</f:facet>
#{t.player}
</h:column>
<h:column>
<f:facet
name="header">
Age
</f:facet>
#{t.age}
</h:column>
<h:column>
<f:facet
name="header">
Birthplace
</f:facet>
#{t.birthplace}
</h:column>
<h:column>
<f:facet
name="header">
Residence
</f:facet>
#{t.residence}
</h:column>
<h:column>
<f:facet
name="header">
Height (cm)
</f:facet>
#{t.height}
</h:column>
<h:column>
<f:facet
name="header">
Weight (kg)
</f:facet>
#{t.weight}
</h:column>
<h:column>
<f:facet name="header">
Coach
</f:facet>
#{t.coach}
</h:column>
<h:column>
<f:facet
name="header">
Born
</f:facet>
<h:outputText value="#{t.born}">
<f:convertDateTime pattern="dd.MM.yyyy" />
</h:outputText>
</h:column>
<f:facet
name="footer">
<div
id="paging">
<ul>
<li>
<a href="#">
<span>Previous</span>
</a>
</li>
<li>
<a href="#" class="active">
<span>1</span>
</a>
</li>
<li>
<a href="#">
<span>2</span>
</a>
</li>
<li>
<a href="#">
<span>3</span>
</a>
</li>
<li>
<a href="#">
<span>4</span>
</a>
</li>
<li>
<a href="#">
<span>5</span>
</a>
</li>
<li>
<a href="#">
<span>Next</span>
</a>
</li>
</ul>
</div>
</f:facet>
</h:dataTable>
</h:panelGrid>
Now, we have
populate the CSS classes listed earlier in a file arbitrary named, styles.css. This CSS file
and a template file are added under a folder named, jsftheme. This is the JSF contract.
Now, we can use it like this:
1.
load the styles.css in template file (template.xhtml)
<h:body>
<!-- the styles.css contains the theme CSS
-->
<h:outputStylesheet
name="styles.css"/>
<div class="content">
<ui:insert name="content"/>
</div>
</h:body>
2.
in the main page (index.xhtml) use the template (template.xhtml) and indicate
the theme (jsftheme)
<h:body>
<f:view contracts="jsftheme">
<ui:composition template="/template.xhtml">
<ui:define name="content">
... <!-- the JSF page code listed earlier -->
</ui:define>
</ui:composition>
</f:view>
</h:body>
The result
is in figure below:
The complete
code is on GitHub [StylingJSF]
Niciun comentariu :
Trimiteți un comentariu