Questions about Trinidad skinning

Skinner questions

This section of the document is aimed to answer frequent questions from skinners.

What is a skinner?

A skinner is someone in charge of writing the skin itself, that is the CSS file.

I can't get my skin to show up

To cause the skinning framework to kick off, you need to do one of the following:

Where do I define my custom skin?

In a nutshell, a skinner creates a skin by creating a css file and using the skin selectors found in the skin-selectors.html document. Example skins are in the demo bundle - purple and beach. Then the skinner creates a skin object by creating a <skin> element in the trinidad-skins.xml file. Child elements are <id>, <family>,<render-kit-id>, <style-sheet-name>, <bundle-name>, <extends>. Then in trinidad-config.xml, the application developer can set the <skin-family>.

I really like this global skinning concept but it would be nice if there was a way to just override a few things in a skin. From what I understand, it's a all of nothing type of approach (speaking from the ADF 10.1.3.2 side) and only an option for the simple skin. I'd like to be able to pick an existing skin but only override a couple of things.

In Trinidad you can! In the trinidad-skins.xml file when you define your skin you can extend any skin you want using the <extends> element. The value of the <extends> element is the id of the skin you want to extend. For example, in the demo bundle we have a sample skin with the id 'purple.desktop'. If you want to create a new skin that is just like the purple.desktop skin but has bigger font, you can create a new skin in trinidad-skins.xml that extends the purple.desktop skin using <extends>purple.desktop</extends>, and all your new skin's css file has to do is override one skinning key .AFDefaultFont:alias {font-size: 18pt;} to increase the font-size.

Where is an example skin that shows me all the skinning features?

In the trinidad-demo project, there is a purple skin defined in trinidad-skins.xml. The skinning css file for the purple skin is in the file purpleSkin.css. In this file, we have tried to put in examples of all the skinning features, like inhibiting styles from base skins with '-tr-inhibit', including other style properties from other style classes with -tr-rule-ref, defining styles specifically when the browser's language is in right-to-left mode with :rtl, using @agent and @platform skinning at-rules to specify styles for a specific agent and/or platform.

I'm a custom component developer, how do I add my skinning definitions to another skin, like the simple.desktop skin?

You add your custom component skinning selectors and css properties to your custom stylesheet. Then, in trinidad-skins.xml, you add a <skin-addition> element. The child elements are <skin-id> and <style-sheet-name>. The <skin-id> will be the id of the skin you are adding your custom stylesheet to, like simple.desktop. The style-sheet-name is the name of your custom stylesheet. trinidad-skins.xml files can now be found inside a jar at META-INF/trinidad-skins.xml.

Should I include a dot before the selector names like af|inputText::content?

No, you MUST NOT include the dot. While skinning, you must not consider af|inputText and such as a style class, but rather as an html element. For example, You can consider more or less the following to be equivalent. Note that you should use the first form while skinning though as you have absolutely no garanteed that panelHeader::level-one will be rendered as a h1.

af|panelHeader::level-one
{
  /* ... */
}

and

h1
{
  /* ... */
}

That being said, you must use dot if you're defining a real class like .AFQuickSelectIcon or an alias like .AFErrorIcon:alias.

Is it possible to insert spacing between fields inside a panelFormLayout without using <tr:spacer/> ?

Yes it is! You can achieve it in the skin simply by adding a padding at the top and/or the bottom of the label and content cells. Here is a sample for doing this:

af|panelFormLayout::label-cell
{
  padding-top: 8px;
}

af|panelFormLayout::content-cell
{
  padding-top: 8px;
}

How can I specify a valid url to an image inside my skin? I'm all mixed up!

Trinidad's skinning engine supports 4 URL types: absolute, relative, context relative and server relative.

Equivalence Most of the times, you can write equivalent URLs in any of the 4 forms. For example, if your web application is located at http:www.mycompany.com/MyWebApp/ and your CSS is located in /skins/mySkin/ folder, the following 4 entries are equivalent:

.AFErrorAnchorIcon:alias
{
  /* Absolute */
  content: url(http://www.mycompany.com/MyWebApp/skins/mySkin/skin_images/ObjectIconError.gif);
}

.AFErrorAnchorIcon:alias
{
  /* Relative */
  content: url(skin_images/ObjectIconError.gif);
}

.AFErrorAnchorIcon:alias
{
  /* Context relative */
  content: url(/skins/mySkin/skin_images/ObjectIconError.gif);
}

.AFErrorAnchorIcon:alias
{
  /* Server relative */
  content: url(//MyWebApp/skins/mySkin/skin_images/ObjectIconError.gif);
}

Why is there so many ways to specify URLs? Is there a preferred type?

The 4 ways to specify an URL exist to offer maximum flexibility to our users. In the majority of cases however, only relative will be used.

Relative is the preferred type when you specify a skin icon because it is the most resistant to directory structure changes. Also, it's very possible that in the future, Trinidad will allow to create JAR archives containing all skin data. Such JAR should be independant of server and context as well as contains every resource it needs and only relative URLs are consistent with that idea.

I would like to give panelBox round borders, is it possible?

Yes you can. panelBox is rendered within a container that allows you to add whatever border you want. For this, you have to provide 8 image files, one for each corners(4) and one for each edges(4). The selectors are:

If you want round borders, simply make the corners round. Take a note that, for best results, start and end edges images should have the same width as the corners while top and bottom edge should have the same height than the corners.

To create the frame you can use something like the following in your skin's CSS file:

/* Default mode */
af|panelBox::top-start
{
  background-image: url(skin_images/TopStartCorner.gif);
  height: 8px;
  width:  8px;
}

af|panelBox::top-end
{
  background-image: url(skin_images/TopEndCorner.gif);
  height: 8px;
  width:  8px;
}

af|panelBox::bottom-start
{
  background-image: url(skin_images/BottomStartCorner.gif);
  height: 8px;
  width:  8px;
}

af|panelBox::bottom-end
{
  background-image: url(skin_images/BottomEndCorner.gif);
  height: 8px;
  width:  8px;
}

af|panelBox::top
{
  background-image: url(skin_images/Top.gif);
  background-repeat: repeat-x;
}

af|panelBox::start
{
  background-image: url(skin_images/Start.gif);
  background-repeat: repeat-y;
}

af|panelBox::bottom
{
  background-image: url(skin_images/Bottom.gif);
  background-repeat: repeat-x;
}

af|panelBox::end
{
  background-image: url(skin_images/End.gif);
  background-repeat: repeat-y;
}

/* RTL mode */
af|panelBox::top-start:rtl
{
  background-image: url(skin_images/TopStartCorner.gif);
  height: 8px;
  width:  8px;
}

af|panelBox::top-end:rtl
{
  background-image: url(skin_images/TopEndCorner.gif);
  height: 8px;
  width:  8px;
}

af|panelBox::bottom-start:rtl
{
  background-image: url(skin_images/BottomStartCorner.gif);
  height: 8px;
  width:  8px;
}

af|panelBox::bottom-end:rtl
{
  background-image: url(skin_images/BottomEndCorner.gif);
  height: 8px;
  width:  8px;
}

af|panelBox::top:rtl
{
  background-image: url(skin_images/Top.gif);
  background-repeat: repeat-x;
}

af|panelBox::start:rtl
{
  background-image: url(skin_images/Start.gif);
  background-repeat: repeat-y;
}

af|panelBox::bottom:rtl
{
  background-image: url(skin_images/Bottom.gif);
  background-repeat: repeat-x;
}

af|panelBox::end:rtl
{
  background-image: url(skin_images/End.gif);
  background-repeat: repeat-y;
}

However, this might not be the wanted result quite yet. panelBox supports 4 different backgrounds (transparent, light, medium and dark), and the above selectors will skin all 4 at the same time. For example, if you want to set the border of dark panelBox only, you have to combine the selectors like this:

/* Default mode */
af|panelBox::dark af|panelBox::top-start
{
  background-image: url(skin_images/TopStartCorner.gif);
  height: 8px;
  width:  8px;
}

/* RTL mode */

af|panelBox::dark af|panelBox::top-start:rtl /* Notice that :rtl is applied only to the LAST selector, else the magic won't work. */
{
  background-image: url(skin_images/TopStartCorner.gif);
  height: 8px;
  width:  8px;
}

My selectors won't work in RTL, what am I doing wrong?

Most likely, you're using combined selectors, if that's the case, make sure the :rtl suffix is added only to the last part of the selector. e.g.

/* Good */
af|panelBox::light af|panelBox::top-start:rtl
{
  /* Style properties */
}

/* Bad */
af|panelBox::light:rtl af|panelBox::top-start:rtl
{
  /* Style properties */
}

Component developer questions

This section is aimed to answer frequent questions from component developer wanting to create new skin enabled components. First, note that skin API is not yet public and is thus not much documented. However, if you feel comfortable with JSF, this section is for you.

Is it possible ot add skin support to my custom components?

Yes it is! But, it requires some footwork:

  1. Your renderer must be part of the org.apache.myfaces.trinidadinternal.core renker kit

  2. Skin access is located inside org.apache.myfaces.trinidadinternal.renderkit.RenderingContext class. So your renderers must access its current instance before anything can work. To access the context, use the following code:

    • RenderingContext context = RenderingContext.getCurrentInstance();
  3. Now you can access a skin style class using context.getStyleClass("yourSkinSelector");

Now there's some things you must know about the selectors you want ot support:

My renderer won't compile because of RenderingContext

RenderingContext is not currently in the public API. Therefore, you have to also include trinidad-impl.jar file in your classpath for the compiler to find it.

Trinidad_Skinning_FAQ (last edited 2009-09-20 23:00:58 by localhost)