ACE Skinning

Table of Contents

Skinning

This article describes the two different ways of skinning a component and explains how the various skin-related resources are prepared at build time to be served by JSF. It also explains how to add more components and skins to this process. Finally, it describes how all CSS files of a skin are merged into one file.

Motivation

JSF 2 has its own resource handling mechanism. It is explained in detail in section 2.6 of the JSF 2.0 specification. The relevant points to this article are the following:

  • Resources are contained in resource libraries.
  • There is a well-defined URL format that must be used to access resources through this mechanism.

Therefore, in ICEfaces, all resources used for skinning components (i.e. CSS and image files) are prepared at build time for JSF 2's resource handling mechanism. Optionally, these resources will undergo an optimization that consists of generating sprite images. In any case, the resulting resources (i.e. modified CSS files and generated images) will ultimately be prepared in the same way for JSF's resource handling mechanism.

Original Files

It is important to first clarify what is meant by original files in this context. These are all the raw, unprocessed skin-related files (i.e. CSS and image files). They are placed, by convention, in a directory named 'skins' inside the component's source directory. However, it is possible to place these files in any location. Inside this directory, there should be a subdirectory for every skin that the component supports. The name of this subdirectory should match the name of the skin across the entire project. For example, at the moment of this writing, the only supported skins are 'sam' and 'rime', so all components that support these skins have subdirectories inside 'skins' named exactly 'sam' and 'rime'.

The CSS files inside these skin directories can reference image files in the usual way (i.e. with relative paths to the image files inside url() expressions). It is important not to reference images that are outside of the skin subdirectory.

Even if two components use the same image, they must have their own copy. The purpose of this is to ease the job of customizing the look of specific components, without affecting others. If sprites are enabled, SmartSprites will automatically detect duplicate images and only include one copy of it in the generated sprite image.

The Build Process

The source files described above will be taken from their original location and placed inside the org.icefaces.component.skins resource library, so that they can be actually served when the application is deployed. The CSS files will be modified so that the URLs of the images they reference are in the format required by the JSF2 resource handling mechanism. Optionally, sprite images for each skin will be generated from all the individual images used by all components supporting that skin.

For example, the original skin files for a determined component could have the following structure.

 ace/component/src/org/icefaces/component/my_component
                                          |
                                          +-- /skins
                                          |     |
                                          |     +-- /sam
                                          |     |     |
                                          |     |     +-- mycomponent.css
                                          |     |     |
                                          |     |     +-- icon.png
                                          |     |
                                          |     +-- /rime
                                          |           |
                                          |           +-- mycomponent.css
                                          |           |
                                          |           +-- icon.png
                                          |
                                          +-- MyComponent.java
                                          |
                                          +-- MyComponentMeta.java
                                          |
                                          +-- MyComponentRenderer.java

At the end of the process, the files would be placed in the org.icefaces.component.skins resource library directory, as illustrated below.

 ace/component/resources/org.icefaces.component.skins
                         |
                         +-- /rime
                         |     |
                         |     +-- /my_component
                         |           |
                         |           +-- calendar.css
                         |           |
                         |           +-- icon.png
                         |
                         +-- /sam
                               |
                               +-- /my_component
                                     |
                                     +-- calendar.css
                                     |
                                     +-- icon.png

The generated sprite images will always be placed directly under a org.icefaces.component.skins/<skin-name> directory. Here is the concrete example for the sam skin:

 resources/org.icefaces.component.skins/sam/sprite.png
 resources/org.icefaces.component.skins/sam/sprite-x.png
 resources/org.icefaces.component.skins/sam/sprite-y.png

This process will be carried out when building the main sparkle project (i.e. by just typing 'ant'). If one only wishes to perform the skins processing, one can just run the 'skins' target (i.e. by typing 'ant skins'). Likewise, one can clean only the skins by running the 'clean-skins' target. The 'skins' target depends on the 'cssurlmapper' target, which builds the tool that carries out the URL mapping.

Sprites and No-Sprites

One can choose to use sprite images or not by setting/unsetting the 'use.sprites' property in the 'build.properties' file. Using sprites is only a performance optimization. The components should look exactly the same whether sprites are used or not. If 'use.sprites' is set, then, at build time, sprite images will be generated using the source images explained above, and the source CSS files will be modified to reference these generated images at the right offsets. More information on sprite generation can be found here. If 'use.sprites' is not set, then all images will be accessed individually.

URL Mapping

The 'cssurlmapper' tool will parse all CSS files (the original ones or the ones generated by SmartSprites) and will map all URLs contained in it to the format required by the JSF2 resource handling mechanism. The build script is configured to place the output files in a specified resource library directory.

For example, the following URL appears in an original CSS file.

 url(images/background.png)

It will be mapped as follows.

 url(#{resource['org.site.lib/images/background.png']})

More specific information about the CSS URL mapper can be found here.

How to add more component skin resources to the build process

New skin resources are added on a per-component, per-skin basis. Each such addition requires a declaration in the build file.

We need to add an 'includeresources' declaration inside the 'skins' target and provide the following three pieces of information:

  • dir: the path to the actual directory that contains the skin resources.
  • name: the name of the component (this name could be anything, as long as it's different for every component).
  • skin: the name of the skin these resources are a part of.

A real example of this declaration would be the following:

 <includeresources dir="src/org/icefaces/component/slider/skins/sam" name="slider" skin="sam" />

If we are creating a completely new skin, then we must also call the task 'generatesprites', specifying its name in the 'skin' attribute. This is done only once per skin. An example of this would be the following.

 <generatesprites skin="rime" />

Concatenating CSS files

When using a skin, each component requires it's own CSS files, which would necessitate manually including all of the CSS files for each component in the page. This would obviously be a burden for the application developer. It would be easier to include a single CSS file that contains the styling for all components for a given skin. This problem is solved by concatenating all of the CSS files for a given skin into a single CSS file. This is done at build time by using the following macro at the end of the 'skins' task:

 <concatskin name="rime" />

Where 'name' refers to the name of the skin. The skin names have to be the same that are used throughout the build script. The resulting files are placed in the 'org.icefaces.component.skins' resource library.They have the exact same name as the skin name specified and have the extenstion .css (e.g. '/resources/org.icefaces.component.skins/rime.css').

Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.

© Copyright 2021 ICEsoft Technologies Canada Corp.