In this blog we are going to see how we can use ADF skin selectors to change look and feel of ADF pages. While going over this topic we will also try to see skinning framework of ADF
Here are the steps we are going to follow
1. Default page with input text.
2. Enable actual classes
3. How ADF is working
4. Derive ADF selector based on ADF classes
5. Register new skin
6. Modify ADF selector and see changes at runtime
1. Default page with input text: Lets create an ADF application with a page (MySkinPage.jsf). Add input text to page and see default skin in chrome.
At runtime page looks like
We can notice few things here
a. ADF generates good amount of html for each ADF component.
b. It styles them by classes but name of these classes are very cryptic like .x25 or .xu
The cryptic class name is actually compressed class name, This makes our html and css code shorter and download time will be faster. Oracle generates these compressed class name at runtime. If we try to directly style these classes as x25/xu etc, we may lose context over time and even oracle may change these class names in future.
In ADF we put our styles against selector and framework reads these selector at runtime and create a class with compressed name. Our aim should be to provide styles against ADF selector.
But how to get actual selector that we should be modifying? One approach is read documentation http://jdevadf.oracle.com/adf-richclient-demo/docs/skin-selectors.html
Another approach could be to stop compression and ask framework to show actual (lengthier) class name. Using that class name we can try to derive selector name. To do this we can follow next step.
2. Enable actual classes: For this we just need to disable compression. We can do it easily by adding following lines in web.xml
<context-param>
<param-name>org.apache.myfaces.trinidad.DISABLE_CONTENT_COMPRESSION</param-name>
<param-value>true</param-value>
</context-param>
As we are going to make changes in style sheet and we would love to see those changes immediately without any need to restart we can modify CHECK_FILE_MODIFICATION property of web.xml to true
Run page and you should see actual class names.
3. How ADF is working
When you enable compression (default mode), ADF tries to convert your skin file and generate new skin file with shorter class names. It finds skin file (css) as configured in trinidad-config/trinidad-skin.xml file and then compress it. While compressing it generates a unique short class name for every valid adf selector. I said valid adf selector for example af|panelLabelAndMessage::content-cell. You can refer http://jdevadf.oracle.com/adf-richclient-demo/docs/skin-selectors.html for all valid selectors.
Now when ADF generates HTML, it will used same compressed short unique names in html as well. For example if af|panelLabelAndMessage::content-cell becomes "x1a2" in new compressed css, then html will also refer "x1a2" as class="x1a2".
When you disable compression then also ADF generates a new skin file. It converts ADF selectors to a valid class name. For example af|panelLabelAndMessage::content-cell will become .af_panelLabelAndMessage_content-cell. Same thing will appear in html as well. Only thing compression will not happen so classes referred in new css and html are not compressed.
One common mistake is done by developers is to disable content compression for debugging and then directly use same style which is appearing in html in css file. For example if you disable compression, class is appearing in html as class="af_panelLabelAndMessage_content-cell". What you may be tempted to directly add below style in css file
.af_panelLabelAndMessage_content-cell {
}
You will see changes immediately and you happily forget about it. Later when you enable content compression, you find that style is no more working. Its because ADF will not compress .af_panelLabelAndMessage_content-cell. This is not valid selector. New CSS will have class as .af_panelLabelAndMessage_content-cell but your html component's class is compressed now.
Make a habit to derive selector name once you get ADF uncompressed class name.
4. Derive ADF selector based on ADF classes:
We can put styles in our css directly against .af_inputText but that is not good practice as framework may changes these class names in future. What we want is to get a selector behind the class and then style that selector. We can always look for documentation and get correct selector. But following rules mostly work
I believe the documentation that we can refer to http://jdevadf.oracle.com/adf-richclient-demo/docs/skin-selectors.html
5. Register New Skin: You can follow blog http://sanjeev-technology.blogspot.in/2015/04/adf-do-you-know-oracle-provided-skins.html
Here are the steps we are going to follow
1. Default page with input text.
2. Enable actual classes
3. How ADF is working
4. Derive ADF selector based on ADF classes
5. Register new skin
6. Modify ADF selector and see changes at runtime
1. Default page with input text: Lets create an ADF application with a page (MySkinPage.jsf). Add input text to page and see default skin in chrome.
At runtime page looks like
We can notice few things here
a. ADF generates good amount of html for each ADF component.
b. It styles them by classes but name of these classes are very cryptic like .x25 or .xu
The cryptic class name is actually compressed class name, This makes our html and css code shorter and download time will be faster. Oracle generates these compressed class name at runtime. If we try to directly style these classes as x25/xu etc, we may lose context over time and even oracle may change these class names in future.
In ADF we put our styles against selector and framework reads these selector at runtime and create a class with compressed name. Our aim should be to provide styles against ADF selector.
But how to get actual selector that we should be modifying? One approach is read documentation http://jdevadf.oracle.com/adf-richclient-demo/docs/skin-selectors.html
Another approach could be to stop compression and ask framework to show actual (lengthier) class name. Using that class name we can try to derive selector name. To do this we can follow next step.
2. Enable actual classes: For this we just need to disable compression. We can do it easily by adding following lines in web.xml
<context-param>
<param-name>org.apache.myfaces.trinidad.DISABLE_CONTENT_COMPRESSION</param-name>
<param-value>true</param-value>
</context-param>
As we are going to make changes in style sheet and we would love to see those changes immediately without any need to restart we can modify CHECK_FILE_MODIFICATION property of web.xml to true
<context-param> <param-name>org.apache.myfaces.trinidad.CHECK_FILE_MODIFICATION</param-name> <param-value>true</param-value> </context-param>
Run page and you should see actual class names.
3. How ADF is working
When you enable compression (default mode), ADF tries to convert your skin file and generate new skin file with shorter class names. It finds skin file (css) as configured in trinidad-config/trinidad-skin.xml file and then compress it. While compressing it generates a unique short class name for every valid adf selector. I said valid adf selector for example af|panelLabelAndMessage::content-cell. You can refer http://jdevadf.oracle.com/adf-richclient-demo/docs/skin-selectors.html for all valid selectors.
Now when ADF generates HTML, it will used same compressed short unique names in html as well. For example if af|panelLabelAndMessage::content-cell becomes "x1a2" in new compressed css, then html will also refer "x1a2" as class="x1a2".
When you disable compression then also ADF generates a new skin file. It converts ADF selectors to a valid class name. For example af|panelLabelAndMessage::content-cell will become .af_panelLabelAndMessage_content-cell. Same thing will appear in html as well. Only thing compression will not happen so classes referred in new css and html are not compressed.
One common mistake is done by developers is to disable content compression for debugging and then directly use same style which is appearing in html in css file. For example if you disable compression, class is appearing in html as class="af_panelLabelAndMessage_content-cell". What you may be tempted to directly add below style in css file
.af_panelLabelAndMessage_content-cell {
}
You will see changes immediately and you happily forget about it. Later when you enable content compression, you find that style is no more working. Its because ADF will not compress .af_panelLabelAndMessage_content-cell. This is not valid selector. New CSS will have class as .af_panelLabelAndMessage_content-cell but your html component's class is compressed now.
Make a habit to derive selector name once you get ADF uncompressed class name.
4. Derive ADF selector based on ADF classes:
We can put styles in our css directly against .af_inputText but that is not good practice as framework may changes these class names in future. What we want is to get a selector behind the class and then style that selector. We can always look for documentation and get correct selector. But following rules mostly work
Example class
|
Corresponding selector
|
Rules applied
|
af_inputText
|
af|inputText
|
Change af_ to af|
|
af_inputText_label
|
af|inputText::label
|
Change af_ to af|
Change second _ to ::
|
af_inputText_content
|
af|inputText::content
|
Change af_ to af|
Change second _ to ::
|
Class inheritance
.af_inputText.p_AFDisabled
.af_inputText_content
|
af|inputText:disabled::content
|
Change af| to af|
Change .p_AFDisabled to :disbaled
Change second _ from ::
[NOTE: inheritance is merged in single selector using : and ::]
|
.af_button.p_AFTextOnly .af_button_text
|
af|button:text-only::text
|
Change af| to af|
Change .p_AFTextOnly to :text-only
Change second _ from ::
[NOTE: inheritance is merged in single selector using : and ::]
|
I believe the documentation that we can refer to http://jdevadf.oracle.com/adf-richclient-demo/docs/skin-selectors.html
5. Register New Skin: You can follow blog http://sanjeev-technology.blogspot.in/2015/04/adf-do-you-know-oracle-provided-skins.html
6. Modify ADF selector and see changes at runtime: For this you just need to add selector entry in your css file and then change styles associated. for example
Note: In ADF we don't put entry of encrypted class or actual class name in css file. We try to set style for selector. At runtime Oracle convert these selectors to appropriate class name.
af|inputText::content { background-color: red; }
Note: In ADF we don't put entry of encrypted class or actual class name in css file. We try to set style for selector. At runtime Oracle convert these selectors to appropriate class name.