Oracle ADF Code Corner: Increase performance of pages that hold custom CSS and JavaScript code

ADF Faces RC: Increase performance of pages that hold custom CSS and JavaScript code

JavaScript code and CSS styles can be placed almost anywhere in a JavaServer Faces page. However, recent testings and inhouse experience at Oracle shows that there is a best practice when adding scripting to a page.

Written by Frank Nimphius, Oracle Corporation
03-Apr-2008

Introduction

Its tempting to put custom CSS and JavaScript into the body part of a ADF Faces RC page because its easy to do and not forbidden. Looking at my blogging samples that use JavaScript, I am guilty too of not implementing best practices. But how would I have known until recently that I found an internal pointer that I like to share with the community.

As it turns out, CSS and JavaScript sources that are added to the page body load slower in IE and FireFox than the same code added to the page header. Below are two strategies for adding those codes into the page header - one for using templates and one for adding it to a single page

Single Page

To add content like JavaScript that is called from a af:clientListener or CSS that is referenced from the class property of a UI component to the page heade, you use the "metaContainer" facet of the af:document element. So in the below example, the JavaScript, which is called from a client side drag and drop listener, will be added to the page header in the downloaded ADF Faces RC page

 <af:document>
<f:facet name="metaContainer">
<af:group>
<![CDATA[
<script>
// return options
// AdfDnDContext.ACTION_NONE
// AdfDnDContext.ACTION_COPY
// AdfDnDContext.ACTION_MOVE
// AdfDnDContext.ACTION_LINK
function handleDropEvent(adfDndContext, proposedAction, pos_x, pos_y){

// not used in this sample. However, you can use it
// to e.g. suppress a drop operation if specific client
// conditions aren't met. In this case you only ned to
// return ACTION_NONE

return AdfDnDContext.ACTION_COPY;
}
</script>
]]>
</af:group>
</f:facet>

...

<af:document>

As you will notice, there is an af:group element within this facet. The reason for this is that "[CDATA]" is not a valid child of facet.

Templates

Templates are cool because they allow reuse and page consistency. Within templates you may want to add common CSS style definitions or JavaScript that should become available on all page. Creating a new template will produce a template page source similar to:

<af:pageTemplateDef var="attrs">
af:facetRef facetName="mainContentArea"/>
<af:xmlContent>
<component xmlns="http://xmlns.oracle.com/adf/faces/rich/component">
<display-name>MyTemplate</display-name>
<facet>
<facet-name>mainContentArea</facet-name>
</facet>
</component>
</af:xmlContent>
</af:pageTemplateDef>

To add JavaScript and CSS source codes to the header part of the template, you need to add the af:document element below the af:pageTemplateDef.

hint: A limitation that exist for Jdeveloper 11 TP3 is that the af:document cannot be added declaratively from the component pallet to the template and that adding it manually will show an eror icon in the right side margin saying that af:pageTemplateDef is not a valid parent for af:document. Ignore that error message and believe me that this will work at runtime. For the JDevelper 11 production release I expect this limitation to be removed.

After adding the af:document with the JavaScript (as an example), the page now should look like

<af:pageTemplateDef var="attrs">
<af:document title="template">
<f:facet name="metaContainer">
<af:group><![CDATA[
<script>
// return options
// AdfDnDContext.ACTION_NONE
// AdfDnDContext.ACTION_COPY
// AdfDnDContext.ACTION_MOVE
// AdfDnDContext.ACTION_LINK
function handleDropEvent(adfDndContext, proposedAction, pos_x, pos_y){

// not used in this sample. However, you can use it
// to e.g. suppress a drop operation if specific client
// conditions aren't met. In this case you only ned to
// return ACTION_NONE

return AdfDnDContext.ACTION_COPY;
}

function sayHello(evt){
alert('Hello ADF World');
}

</script>
]]>
<af:facetRef facetName="metaContainer"/>
</af:group>
</f:facet>
</af:document>
<af:facetRef facetName="mainContentArea"/>
<af:xmlContent>
<component xmlns="http://xmlns.oracle.com/adf/faces/rich/component">
<display-name>MyTemplate</display-name>
<facet>
<facet-name>metaContainer</facet-name>
</facet>
<facet>
<facet-name>mainContentArea</facet-name>
</facet>
</component>
</af:xmlContent>
</af:pageTemplateDef>

Note that the "metaContainer" facet contains a facet reference that will allow application developers to add more codes to the af:document metaContainer after applying the template to a page. The page source of a ADF Faces RC page using this optimized template will look similar to

<?xml version='1.0' encoding='windows-1252'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
<jsp:directive.page contentType="text/html;charset=windows-1252"/>
<f:view>
<af:document>
<af:form>
<af:pageTemplate viewId="/optimizedTemplate.jspx">
<f:facet name="metaContainer"/>
<f:facet name="mainContentArea">
<af:commandButton text="Click me to say hello" partialSubmit="true">
<af:clientListener method="sayHello" type="click"/>
</af:commandButton>
</f:facet>
</af:pageTemplate>
</af:form>
</af:document>
</f:view>
</jsp:root>


Summary

Though it is tempting to add JavaScript and CSS sources to where you need them, proven best practice is to ensure they are added to the header of a page. To do this with ADF Faces RC, you use the metaContainer facet of the af:document element, which can be done on a single page and on templates, which then are used with multiple pages. Still, if you need to use JavaScript and CSS to be in the body part of a page, you can do this in templates and pages

 

E-mail this page
Printer View Printer View
Oracle Is The Information Company About Oracle | Oracle RSS Feeds | Careers | Contact Us | Site Maps | Legal Notices | Terms of Use | Privacy