Blog Archives

December 6th, 2010
10:45 am
Customising the Primefaces Breadcrumb control

Posted under JSF
Tags , , , , ,

This control has a preview mode which dynamically shrinks and expands the links on hover. Nice idea, but it’s rather slow to render the page on load when there are many entries, as the initial compress is done by jQuery so lots of JavaScript going on.

My preference when a lot of entries are present would be to render the control statically, and instead of dynamically expanding the entries, to have them permanently compressed but with tooltips (= html title attribute) to show the full entry on hover (as suggested here in Jenifer Tidwell’s excellent book Designing Interfaces). This would be much faster.

Unfortunately, the current control does not support that – the menu item children that make up the breadcrumb entries do have a ‘help text’ attribute which looks like it should render a title/tooltip but this does not work.

I would like at some point to make a custom version. The best way would probably be to make it a new different control, possibly in my own library but at least as an additional Primefaces control that I could easily deploy on new released without having to customise code.

Chapter 11 of Core JavaServer Faces has a good example walkthrough of a full custom component development, which helps to give a background. Customising the breadcrumb looks easy as it is just a question of enhancing existing code by adding some additional attributes and changing the encoding in the renderer to encode titles and do a static breadcrumb. The following functionality would be needed:-

ToolTipMode attribute to turn on the new mode. Other modes would possibly still be present  – no point in disabling them unless I have too. If it looks like carrying the old modes is a lot of baggage I could create a stripped down control using the old one as a framework, and only support the new modes I require. As I am keeping the existing control there is no need to duplicate its features if I don’t need to. As the rendering for the new control should be straightforward, I could even rip out all the jQuery stuff and just use some of the existing CSS techniques for rendering it, but statically. I would duplicate the classes and give my own names.

In the new mode, all entries would have a hover title.

  • ToolTipCompressThreshold attribute would be a character count for the whole breadcrumb which would trigger compression of all entries equally. This is obviously a static guess figure, but it avoids having to do any client side stuff in JavaScript and so will render fast.
  • ToolTipMaxLength attribute would be a notional maximum length in pixels for the breadcrumb (set separately from the css). When the compress threshold has been reached, this attribute would be divided by the number of breadcrumb entries to be rendered, and the resulting value used as the maximum pixel size for rendering each entry (it would be good to allow them to be shorter if they don’t use all the space, so it does not look odd). Rather than strip out characters from the entries, I would just hide the excess width via a hidden overflow in a div (as the existing control does now).

The source is all available in the source or bundled zip download. Note the following from a first look:-

  • BreadCrumb.java contains the properties for all the attributes – all driven from an enum with custom methods in it (note the technique, could use this as it enforces consistency and avoids typos etc.)
  • BreadCrumbRenderer.java renders all the html and js calls.
  • BreadCrumbTag.java – note that Primefaces 2.2M1 had this file, but 2.2RC2 does not have it. Check/compare the code – they either simplified it or it has gone missing from the latest release. I could base my version on either.
  • MenuItem.java – will probably want to look at this as each BreadCrumb item is a menu item.
  • primefaces-i.taglib.xml and primefaces-p.taglib.xml are the taglibs – I will need to define a taglib for mine (see core Javaserver faces again). Note that these are in the deployed jar but not in the sources jar.
  • faces-config.xml – defines all the component classes. As with the taglibs this is in the deployed jar but not the sources jar.

No Comments »

November 30th, 2010
4:37 pm
Tailoring a Primefaces TreeTable with JavaScript/jQuery/JSF 2.0

Posted under JSF
Tags , , , , , , , ,

This example came about from the desire to hightlight a Primefaces TreeTable row when a checkbox in the row is ticked. I wanted to do this because a ticked checkbox is not as visible as I would like when a lot of data is present. I was not keen on adding DataTable style dynamic selection by hovering and clicking anywhere in a row, as this conflicts somewhat with the paradigm of clicking on the expander to expand/collapse the tree, and you would have to special case hovering/clicking on the expander somehow to prevent row selection.

Ideally you would use CSS for this, but this would involve tagging a component in a TreeTable cell (<td> element) with a class (as in the TreeTable component we cannot directly add row styling), and then using some kind of ancestor selector to traverse the DOM tree upwards to get the row. The simple answer to this is that whilst CSS can do some clever things, it does not have any kind of ancestor selector, so it is not possible to do it just with CSS.

An attractive alternative for this kind of thing in Primefaces is to use jQuery – a very powerful JavaScript based UI library upon which Primefaces is based. As it is already present in a Primefaces environment, it is trivial to call and ideal for this kind of thing. In particular, it has powerful mechanisms for traversing and searching the DOM tree and selecting elements etc. If you combine this with its features for dynamically adding and removing classes from elements, it can do exactly the kind of thing that we cannot do in CSS. The jQuery website is here, and the API documentation for it may be found here.

The sample code fragments below demonstrate the idea. The sample is based on a hacked version of the the Primefaces showcase TreeTable demo. Note the following points:-

  • It is perfectly possible to add both Javascript and JSF EL inline inside a JSF component, such that the JavaScript runs at that point when the page is rendered. This example adds some JavaScript inside the JSF tags for a checkbox.
  • As the example uses JavaScript, the hightlight is added/removed both client side from a click event on the check box, and when the page is rendered based on the current check box value in the TreeTableDocument object from the server.
  • The sample uses the JSF 2.0 EL implicit object reference component.clientId to get the client ID of the component where the EL reference is used. This is new for JSF 2.0 (previously additional code would be needed for this) and like the cc implicit object used with composite components, is not at all well documented. I was unable to find reference documentation for it anywhere in the JSF 2.0 specs, but found details of it here (at the end of the post). Note that the reference needs to be placed with care – it sometimes appears to come up with ‘ghost’ client IDs which may have been allocated by JSF but do not actually appear anywhere as IDs in the HTML. When using it, check that it returns the correct ID, for example by just placing a bare #{component.clientId} on the page directly adjacent to where you are using it, and view the source of the generated page in the browser to check that the client ID it returns matches the id of the component it is used for.
  • Be careful to consider any ordering issues – the inline JavaScript call I am using must be placed on the page after the component it refers to has been rendered. By default, using component.clientId  inside a script block which is in turn inside the checkbox component tags causes the script block to be output immediately prior to the html for the checkbox. Therefore, I use two script blocks – one inside the checkbox to save the component ID in a temporary JavaScript variable, which guarantees that I obtain the correct component ID and not an incorrect or ‘ghost’ one, and then another script block immediately after the closing tag for the checkbox component which passes the form ID and saved component ID to a JavaScript function which calls jQuery to do the highlighting after the html element has been rendered on the page. Note that the client side onClick() event on the checkbox will always run after  the full page has been rendered, when the user clicks the box, so ordering is not an issue for this.
  • The call to jQuery passes in the checkbox DOM element, which jQuery wraps with a jQuery object and returns. The parent() method is then used twice to traverse the DOM tree up from the check box to the table cell <td>, and thence to the table row <tr>. The addClass() and removeClass() methods are then used to dynamically add/remove the required CSS classes to the table row depending on the passed check box state. Adding and removing classes with jQuery is useful as it does all the string bashing for you to check if the class being added/removed is already present, handles spaces correctly, and leaves all other classes on the element intact.
  • Note that in an earlier version I had tricky issues with nested quotes in JSF EL. I initially used outer double quotes, with inner single quotes on the JavaScript calls. The EL through this out however. I ended up using double quotes throughout, and escaped the inner ones with backslashes (\). This worked fine. The version shown here does not need this as it is a later modification.
  • The example extends the Primefaces Document class used in the showcase, adding a boolean property for the check box value.
  • My example uses CDI, whereas the original showcase uses JSF managed beans.

Sample Code Fragments

Index.xhtml

<!DOCTYPE HTML>
<html xmlns="http://www.w3c.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:fn="http://java.sun.com/jsp/jstl/functions"
xmlns:p="http://primefaces.prime.com.tr/ui"
xmlns:c="http://java.sun.com/jsp/jstl/core"   
xmlns:util="http://java.sun.com/jsf/composite/uk.co.salientsoft/util">
<f:view contentType="text/html">
<h:head>
    <util:themeSwitcher    outputStyle="true"
                        themeBase="/resources/themes"
                        defaultTheme="redmond"/>
<style>
    .ui-widget {
        font-size: 75% !important;
    }
    h1.header {
        font-size: 1.2em !important;
        padding: 5px;
        margin: 0px 0px 20px 0px;
    }
    h2.subheader {
        font-size: 0.9em !important;
        padding: 2px;
        margin: 0px 0px 10px 0px;
    }
    .float {
        float: left;
    }
   
    .clear {
        clear: both;
    }
    .themeswitcher {
        float: left;
        clear: both;
        margin-bottom: 10px;
    }   
    .ss-selectcolumn {
        width:30px !important;
        padding:0px !important;
        text-align:center;
    }
    .ss-checkbox {
        color:red!important;
    }
/* treetable arrow light/dark switch
    .ui-treetable tr.collapsed td .expander {
        background-image:url("/TreeTable1/javax.faces.resource/treetable/images/toggle-expand-light.png.jsf?ln=primefaces&amp;v=2.2.RC2");
    }
    .ui-treetable tr.expanded td .expander {
        background-image:url("/TreeTable1/javax.faces.resource/treetable/images/toggle-collapse-dark.png.jsf?ln=primefaces&amp;v=2.2.RC2");
    }   
*/
/* Styling nicked from default.css in the Primefaces Showcase */
    a {text-decoration: none;}
    a:hover {text-decoration: underline;}
    a img {border: none;}   
</style>

<script type="text/javascript">
//<![CDATA[
    function highlightTreeTableRow(formId, checkBoxId) {
        var checkBox = document.forms[formId][checkBoxId];
        if (checkBox.checked)
            jQuery(checkBox).parent().parent().addClass(‘ui-state-highlight ui-selected’);
        else
            jQuery(checkBox).parent().parent().removeClass(‘ui-state-highlight ui-selected’);
    }
//]]>
</script>
</h:head>
<h:body>
<h1 class="float header ui-widget ui-widget-header ui-corner-all" style="">Theme Switcher</h1>
<h:form prependId="false" id="frmTest">
<util:themeSwitcher form="frmTest" outerStyleClass="themeswitcher" style="margin-bottom:20px;"/>
<br/><br/>

<div style="width:600px;clear:both;">
    <p:treeTable value="#{documentsController.root}" var="document"
       styleClass="#{(document.name==’logo.png’)? ‘ui-state-highlight ui-selected’:’fred’}"
        expanded="true">
        <p:column>
            <f:facet name="header">
                Name
            </f:facet>
            <h:outputText value="#{document.name}" />
        </p:column>
       
        <p:column>
            <f:facet name="header">
                Size
            </f:facet>
            <h:outputText value="#{document.size}" />
        </p:column>
       
        <p:column>
            <f:facet name="header">
                Type
            </f:facet>
            <h:outputText value="#{document.type}" />
        </p:column>
       
        <p:column>
            <f:facet name="header">
                Options
            </f:facet>
            <p:commandLink update="documentPanel" oncomplete="documentDialog.show()" title="View Detail">
                <p:graphicImage value="/images/search.png"/>
                <f:setPropertyActionListener value="#{document}" target="#{documentsController.selectedDocument}" />
            </p:commandLink>
        </p:column>
       
        <p:column styleClass="ss-selectcolumn">
            <f:facet name="header">
            <h:selectBooleanCheckbox disabled="true" label="box header"/>
            </f:facet>
            <h:selectBooleanCheckbox value="#{document.selected}"
                 
onclick="highlightTreeTableRow(‘frmTest’, this.id);" styleClass="ss-checkbox" id="selector" >                
                 <script>selectId = ‘#{component.clientId}’;</script>
            </h:selectBooleanCheckbox>
            <script>highlightTreeTableRow("frmTest", selectId);</script>
        </p:column>
    </p:treeTable>
    <p:commandButton type="submit" value="Submit" onclick="submit();" style="margin-top:10px;"/>
   
    <p:dialog header="Document Detail" fixedCenter="true" effect="FADE" effectDuration="0.3"
        widgetVar="documentDialog" modal="true">
   
        <p:outputPanel id="documentPanel">
            <h:panelGrid  columns="2" cellpadding="5">
                <h:outputLabel for="name" value="Name: " />
                <h:outputText id="name" value="#{documentsController.selectedDocument.name}" style="font-weight:bold" />
               
                <h:outputLabel for="size" value="Size: " />
                <h:outputText id="size" value="#{documentsController.selectedDocument.size}" style="font-weight:bold" />
               
                <h:outputLabel for="type" value="Type " />
                <h:outputText id="type" value="#{documentsController.selectedDocument.type}" style="font-weight:bold" />
            </h:panelGrid>
        </p:outputPanel>
    </p:dialog>
    </div>
</h:form>
</h:body>
</f:view>
</html>

DocumentsController.java (modified from Showcase)

package org.primefaces.examples.view;
import java.io.Serializable;
import java.util.logging.Logger;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
import org.primefaces.model.DefaultTreeNode;
import org.primefaces.model.TreeNode;
import uk.co.salientsoft.treetable.view.TreeTableDocument;

@Named
@SessionScoped
public class DocumentsController implements Serializable {
   
    private static final long serialVersionUID = -3593168523028092346L;
    private static final Logger logger = Logger.getLogger(DocumentsController.class.getName());
    private TreeNode root;
    private TreeTableDocument selectedDocument;
    public DocumentsController() {
        root = new DefaultTreeNode("root", null);
       
        TreeNode documents = new DefaultTreeNode(new TreeTableDocument("Documents", "-", "Folder"), root);
        TreeNode pictures = new DefaultTreeNode(new TreeTableDocument("Pictures", "-", "Folder"), root);
        TreeNode music = new DefaultTreeNode(new TreeTableDocument("Music", "-", "Folder"), root);
       
        TreeNode work = new DefaultTreeNode(new TreeTableDocument("Work", "-", "Folder"), documents);
        TreeNode primefaces = new DefaultTreeNode(new TreeTableDocument("PrimeFaces", "-", "Folder"), documents);
       
        //Documents
        TreeNode expenses = new DefaultTreeNode("document", new TreeTableDocument("Expenses.doc", "30 KB", "Word Document"), work);
        TreeNode resume = new DefaultTreeNode("document", new TreeTableDocument("Resume.doc", "10 KB", "Word Document"), work);
        TreeNode refdoc = new DefaultTreeNode("document", new TreeTableDocument("RefDoc.pages", "40 KB", "Pages Document"), primefaces);
       
        //Pictures
        TreeNode barca = new DefaultTreeNode("picture", new TreeTableDocument("barcelona.jpg", "30 KB", "JPEG Image"), pictures);
        TreeNode primelogo = new DefaultTreeNode("picture", new TreeTableDocument("logo.jpg", "45 KB", "JPEG Image"), pictures);
        TreeNode optimus = new DefaultTreeNode("picture", new TreeTableDocument("optimusprime.png", "96 KB", "PNG Image"), pictures);
       
        //Music
        TreeNode turkish = new DefaultTreeNode(new TreeTableDocument("Turkish", "-", "Folder"), music);
       
        TreeNode cemKaraca = new DefaultTreeNode(new TreeTableDocument("Cem Karaca", "-", "Folder"), turkish);
        TreeNode erkinKoray = new DefaultTreeNode(new TreeTableDocument("Erkin Koray", "-", "Folder"), turkish);
        TreeNode mogollar = new DefaultTreeNode(new TreeTableDocument("Mogollar", "-", "Folder"), turkish);
       
        TreeNode nemalacak = new DefaultTreeNode("mp3", new TreeTableDocument("Nem Alacak Felek Benim", "1500 KB", "Audio File"), cemKaraca);
        TreeNode resimdeki = new DefaultTreeNode("mp3", new TreeTableDocument("Resimdeki Gozyaslari", "2400 KB", "Audio File"), cemKaraca);
       
        TreeNode copculer = new DefaultTreeNode("mp3", new TreeTableDocument("Copculer", "2351 KB", "Audio File"), erkinKoray);
        TreeNode oylebirgecer = new DefaultTreeNode("mp3", new TreeTableDocument("Oyle bir Gecer", "1794 KB", "Audio File"), erkinKoray);
       
        TreeNode toprakana = new DefaultTreeNode("mp3", new TreeTableDocument("Toprak Ana", "1536 KB", "Audio File"), mogollar);
        TreeNode bisiyapmali = new DefaultTreeNode("mp3", new TreeTableDocument("Bisi Yapmali", "2730 KB", "Audio File"), mogollar);
    }
    public TreeNode getRoot() {return root;}
    public void setRoot(TreeNode root) {this.root = root;}
    public TreeTableDocument getSelectedDocument() {return selectedDocument;}
    public void setSelectedDocument(TreeTableDocument selectedDocument) {
        this.selectedDocument = selectedDocument;
    }
}

TreeTableDocument.java

package uk.co.salientsoft.treetable.view;
import org.primefaces.examples.domain.Document;

public class TreeTableDocument extends Document {
    private static final long serialVersionUID = 7339615098050125785L;
    public TreeTableDocument(String name, String size, String type) {
        super(name, size, type);
    }   
    private boolean;
    public boolean isSelected() {return this.selected;}
    public void setSelected(boolean selected) {this.selected = selected;}
}

No Comments »

November 23rd, 2010
11:38 am
Using floats to place a border around a control group/toolbar

Posted under CSS
Tags , , , , , , ,

I originally used display:inline-block, line-height and vertical-align:middle to do this as detailed here, but the results were inconsistent across browsers.

Using floats is a much better solution for a number of reasons – details are as follows:- 

  • The controls are floated left inside a div which is itself floated left. As the div is floating, it auto resizes to fit around the content, and so scales to fit unknown control sizes.
  • The controls are all set to have fixed top and bottom margins (4px in the example), and the leftmost and rightmost also have similar left and right margins respectively.
  • The floated div is set to have the desired border and background etc. – in my case, I use Primefaces/jQuery UI theme style classes to apply theme look and feel.
  • The floated div is then placed inside another outer div, which may be of fixed dimensions. This allows the control group to adjust in size, but to be located inside a fixed area on a page.
  • If the outer div is of fixed size and non floating, the floating inside it is invisible to the rest of the document, so it is not necessary for example to clear the float.
  • If desired, the outer div can be set to overflow:auto to allow scroll bars if the size of the inner floating div exceeds the space allocated for it on the page.
  • If the area surrounding the control group is also floating, the outer div can also be set to float with no size specified, so the concept works well in both floating and fixed size situations.
  • display:inline-block and vertical-align:middle are not used with this method.

 This mechanism has the following characteristics:-

  • The control group bordering works nicely and consistently with the Primefaces/jQuery theme styling, as rather than trying to centre the controls in a fixed border, instead we vary the border size and keep the margin between the controls and the border constant.
  • The approach makes use of the laws of Gestalt Psychology – the eye notices even small imperfections in the alignment of the controls and their relationship to the border because they are close and obviously grouped/related.
  • Conversely the position of the entire bordered control group within its surroundings (the outer div) will typically not be so critical – it will likely be in a larger area of white space between it and adjacent items,  and so its position and size within that space matters less than the control / border relationship.

A caveat to all this is that it is still not perfect – the simple example below does not perform quite as well in terms of cross browser alignment as the Primefaces/jQuery UI version, as the Primefaces themes apply their own styling as well which changes the situation. This could of course be improved by adjusting the margins individually for different controls in the group to get the best overall cross browser alignment. One very important goal I am trying to acheive is to avoid browser specific CSS. The Primefaces/jQuery UI CSS does in general have browser specific tweaks which will help it in certain situations.

Overall though this approach performs significantly better than the previous method using vertical-align:middle etc. and has the advantage of being fully floating/dynamically sizing if required. An example of this approach follows :-

<!DOCTYPE html>
<html>
<head>
 <style type=”text/css”>
  .ss-outerdiv {
   height: 40px;
   width: 200px;
   background-color: orange;
  } 
  .ss-controlgroup {
   float: left;
   background-color: green;
   border: 1px solid black;
  }
  .ss-select, .ss-leftbutton, .ss-rightbutton {
   margin-top: 4px;
   margin-bottom: 4px;
   float: left;
  }
  .ss-select {
   width: 120px;
     font-family: Arial,Verdana,sans-serif;
     font-size: 11px;    
   margin-left: 4px;
   margin-right: 4px;
  }
  .ss-leftbutton, .ss-rightbutton {
   height: 20px;
   width: 30px;
  }
  .ss-leftbutton  {margin-right: 2px;}
  .ss-rightbutton {margin-right: 4px;}
 </style>
</head>
<body>
<div class=”ss-outerdiv”>
 <div class=”ss-controlgroup”>
  <select class=”ss-select”>
  <option value=”Test”>Test Value</option>
  </select>
  <button class=”ss-leftbutton ss-button”></button>
  <button class=”ss-rightbutton ss-button”></button>
 </div>
</div>
</body>
</html>

No Comments »

November 16th, 2010
2:59 pm
JSF 2.0 Composite Components

Posted under JSF
Tags , , , , , ,

This post highlights a few lessons learned whilst experimenting with a simple composite component, in this case an experimental  Primefaces theme switcher component. The component does the following:-

  • Automatically iterates the themes directory on the server to build a list of available themes which are presented for the user to select
  • Generates a simple theme control panel with a border, consisting of a drop down combo listing the themes, with previous theme/next theme buttons to the right.
  • Also allows theme switching via ctrl/shift/left arrow and ctrl/shift/right arrow, to give a quick way of cycling through the themes when choosing one.
  • The component is used on the JSF page in two modes – the first usage is with outputStyle=”true”, themeBase and defaultTheme attributes. It is placed in the <head> section, and it defines the base path for all the theme directories, and the default starting theme (which may be programmatically overriden by setting the theme property in its backing bean, themeSwitcherBean). This mode also outputs the link directive to link the current theme stylesheet to the page. It does not result in the display of the control panel.
  • The second mode is used inside a <form> on the page, and results in the theme switcher panel being displayed.
  • A theme switch results in a form submission, so this must be acceptable to the form logic. If not, i.e. if the form is dirty, the theme switcher must be disabled. This would be done by passing a disable flag attribute to the component, which maps to a disable property of the backing bean, which results in enabling/disabling the controls. At present, a disable feature is not supported.

 

The following salient points were picked up along the way:-

  • The component does not have to be placed in a form. The examples in the Core JavaServer Faces book seemed to always show the client page with the control placed on a form, and also with <form></form> tags present in the custom component implementation. There is absolutely no requirement for the custom component implementation definition to be in its own form.
  • With JSF 2.0, it is easy to pass a value e.g. from a composite component attribute in a call, direct to a backing bean property, as JSF 2.0 now supports method expressions with parameters in EL expressions – just add the brackets and the call arguments. This used to be tricky, and many posts on technical blogs just seemed to answer ‘why on earth do you want to’. Well, perhaps it is unusual, but in this example it feels just the right thing. Normally when linking to a style sheet, one would put the path to the sheet directly on the page in the <link> tag, as one also would when referring to other resources such as images. I have therefore done exactly the same with the themeswitcher – you pass the theme base web context path (along with the default theme name) to the component just as you would do to a <link> tag. This then allows the backing bean to discover the physical theme directory location on disk and automatically iterate it to generate a list of the available themes which are present, which is then passed to the select list of the combo. Whilst the theme base context path could be set up as an injected property of the backing bean, it just does not feel right to do it that way, as normally this knowledge is encapsulated on the page. Sometimes, passing values from the page to a bean is actually the right thing to do!
  • When using an EL method expression to write to a bean property, note that you can just call a setter on the bean directly as if it was a method, giving the “set” prefix, and passing the value as an argument. You literally just plant the EL call on its own in the middle of the page. (You can of course also use another custom method if you wish, for example if you want to pass a number of properties in a single call). Furthermore, when calling for example a setter or any other method that returns void, nothing is written to the page, as you would expect. In the example code below, the EL expression #{cc.attrs.bean.setThemeBase(cc.attrs.themeBase)} does exactly this.
  • A composite component acts as a JSF naming container. Naming containers are required to ensure uniqueness of IDs on a page , by modifying Ids to add a prefix. For example a composite component could be placed many times on a page, and the Ids of all its constituent components/controls must be unique. As a test example, when the above component was placed in the <head> section (i.e. not in a form), its clientId was j_idt4. When placed on the page a second time, in the form to show the control panel , its clientId was frmTest:j_idt9. Notice that by default the clientId was automatically prefixed by the form ID. This issue becomes important when Javascript is in use to refer to controls in the component, as the Id given to a control is in turn prefixed by the clientId. For example, when on the form, a select box which was given an Id of cmbTheme actually ended up with an id of frmTest:j_idt9:cmbTheme. This needs to be taken account of in the code. Note that in the Javascript examples in Chapter 9 of Core JavaServer Faces (p369), the form is inside the composite component. This turns things around, as the form ID is then prepended by the clientId of the composite component as the latter is a naming container – our case is different.
  • By default a form’s controls have the form id prefixed to their id, as the form is also a naming container. This behaviour can be disabled if desired by adding the attribute prependId=”false” to the form tag, but I did not do this.
  • JSTL functionality can be used such as c:if, and for example you can test parameters passed to composite components (cc.attrs.attrname)– the themeswitcher example uses this with the outputStyle attribute to determine whether to output a <link> tag for the theme stylesheet and set the theme base directory/default theme, or whether to output the themeswitcher control panel. The use of c:if in this way is a powerful means of controlling exactly what a custom component renders on the page, and is a useful alternative to using the render property on a component to prevent it being rendered. In addition, it can for example conditionalise the setting of backing bean properties from the page, as is done in the themeswitcher, which could not be done via toggling the render property on components.  In this case, it seemed more convenient and clearer to give two modes to the same component, so that all the design decisions where encapsulated and visible in one place, rather than inventing another component. Other examples of where this might be useful is where a general purpose composite component might be tailorable via its call attributes. For example a table component might have adjacent up/down buttons to allow re-ordering/moving of a block of selected rows, but the re-order capability might not always be needed, so it could be conditionally selected with c:if.
  • When using JSTL, there are limitations. As an example, I tried c:set to copy an attribute containing the backing bean reference to another variable, to use later in a subsequent instance of the composite component and save passing it twice. Setting a valueChangeListener using the saved copy of the bean reference gave a run time error and is not supported. However, reading and writing properties on the bean using the saved copy of the reference worked fine.
  • Note that other JSTL functions can also be used, e.g. to return the size of a string or list, as noted here.

Comments Off on JSF 2.0 Composite Components

November 11th, 2010
12:59 pm
Scrollable containers in Primefaces

Posted under CSS
Tags , , ,

Some Primefaces containers appear to support scrolling, but this is not universally supported. Layout panels support it, but ordinary panels appear not to.

Fortunately, with IE7 and above, scrolling on a <div> (JSF panelGroup with layout=”block”) works reliably and consistently across modern browsers, so scrolling can just be added within e.g. within a CSS class rule as follows:-

.ss-scroll {
   overflow:auto;
}

or:-

.ss-scroll {
   overflow: scroll;
}

Using overflow:auto will only add the scrollbars if they are needed, i.e. if content is clipped. Using overflow: scroll will add them all the time so you will get redundant scrollbars when the content does not clip.

Note that for Primefaces, to make a scrolling panel for example, the attribute needs to be added to a containing div inside the panel, and not the panel itself, otherwise the panel header will scroll out of view when the contents scroll which is undesirable.

The w3schools documentation on overflow will be found here.

No Comments »

November 11th, 2010
11:35 am
Fonts reduce in size when Primefaces table moved inside a panel

Posted under CSS
Tags , , , ,

Update 22/09/2011

The following selector (as documented below) did not work when used for a particular table. CSS ignored the rule presumably for reasons of specificity:-

.ss-nested-widget, .ss-nested-widget .ui-datatable {
     font-size: 100% !important;
}

However, the following selector did work (and was also modified to include a dialog as well as a table). This has the advantage of not relying on having ss-nested-widget as a class on the table in order to work.
This has now been adopted as standard as the solution for this issue :-

.ss-nested-widget,
.ui-widget .ui-datatable,
.ui-widget .ui-dialog { 
     font-size:100% !important;   
}

Original Post

This issue is due to font size inheritance.

My default font for all Primefaces components was specified globally as follows:-

.ui-widget {

font-size: 75% !important;

}

The reason for this is that in general it is considered more flexible to go for percentage sizes as these can then be scaled automatically when viewed on smaller devices.

Unfortunately, it appears that when for example a table is nested inside a panel, the font size appears to be 75% of 75% as the rule is inherited and applied twice, as 75% is a relative measurement, The table ends up rendered as a 9px font which is too small. The situation is further complicated by the fact that in the Primefaces skinning, there is a mixture of fonts specified in ems, percentages and pixel sizes, which means that not everything is specified in relative sizing anyway.

There are 2 solutions to the issue, both are straightforward, 1/ is the simplest although arguably not the best due to absolute sizing:-

1/ Change the global ui-widget rule above to use a fixed font size (12px works as a replacement for the above 75%)

.ui-widget {

font-size: 12px !important;

}

2/ Keep the  75%  for ui-widget and introduce a new rule to specify a 100% size for nested elements:-

.ss-nested-widget {

font-size:100% !important;

}

This rule needs to be introduced inside the panel. If it is placed on the panel itself, which is the parent element, then the font size just ‘goes large’ to 100%, i.e. larger than the desired default font. To obtain the correct behaviour, the sub-elements inside the panel must be tagged with the style class. It is possible to tag an enclosing <div> just inside the panel, so that the sub-elements inherit it. However, whilst this worked for input selectors and buttons in the panel, tables refused to play ball, and the following rule was needed to ensure that a table in the panel inherited the correct size:-

.ss-nested-widget, .ss-nested-widget .ui-datatable {

font-size: 100% !important;

}

The same kind of trick can be used to target other nested elements which do not inherit the correct size.

An alternative method would be just to add the class to sub-elements individually where required.

No Comments »

November 4th, 2010
1:54 pm
How to add inline Javascript to a Facelets/XHTML page

Posted under JSF
Tags , , , ,

This is not immediately obvious; the following are the key points:-

  • The Javascript code between the script tags needs to be embedded in XML “CDATA” sections
  • The CDATA open and close tags need to be preceded with Javascript comment markers “//”
  • You can freely use JSF Expression language within the Javascript and it will be evaluated and inserted (as with the “request.contextPath” below)

The following example xhtml page illustrates this:-

<!DOCTYPE HTML>
<html xmlns=’http://www.w3c.org/1999/xhtml’
   xmlns:f=’http://java.sun.com/jsf/core’
   xmlns:h=’http://java.sun.com/jsf/html’>
<f:view contentType=”text/html”>
<h:head>
<script type=”text/javascript”>
//<![CDATA[
    alert(“Hello World from #{request.contextPath}”);
//]]>
</script>
</h:head>
<h:body></h:body>
</f:view>
</html>

No Comments »

September 26th, 2010
11:28 am
Choosing a DOCTYPE for maximum browser compatibility and standards mode

Posted under HTML
Tags , , , , , , ,

This follows on from my previous post which highlighted an example of a valid DOCTYPE which still threw IE into Quirks mode.

The DOCTYPE issue has been something of a minefield – there are a number of different declarations and they are relatively complex, some have browser compatibility issues, and then of course different ones are needed for XHTML/facelets use.

It seems the holy grail of simplifying all of this is just to stick to the remarkably simple and highly compatible HTML5 DOCTYPE:-

<!DOCTYPE html>

  • This has the following highly desirable characteristics:-
  • It triggers standards mode for all known modern browsers
  • It is backwards compatible
  • It works with HTML pages and facelets/XHTML

See these posts here, here and here for more discussion on this.

It really does seem to solve all the DOCTYPE pain – I think I’ve died and gone to heaven!

No Comments »

September 18th, 2010
11:08 am
Using display:inline-block and vertical-align in CSS

Posted under CSS
Tags , , , , , ,

Update 23/11/2010

Having experimented with this extensively on different browsers, I have found inconsistent results across browsers when trying to vertically centre a group of controls in a bordered div which closely surrounds them. If you need just a few pixels between the controls and the border, vertical centering does not work in a consistent browser independent manner. For larger centring, e.g. for centring a paragraph of text in a large div, the differences may not be noticeable, but at small scale they definitely are. For placing a close border around a group of related controls, my preferred method is now to use floats as detailed here. Note that the fact that floats are used does not force the rest of the document to use floats or to have non fixed sizing – the floats can be invisible to the outside due to a second outer non floated fixed size div. Also, the floated version works better when the contained controls are of variable or unknown size.

Original post

I originally used this here in order to centre the text on a Primefaces button, the usage of inline-block was incorrect.

What it does not do is allow you for example to centre a <span> element vertically and/or horizontally in a parent div!

What it does do is to allow setting of the alignment of an inline element relative to adjacent inline elements on a line (not relative to the parent container). It will therefore work within a <td> but not within a <div>

There appear to be a lot of fuzzy and partly incorrect articles on the net about this, and it was hard to find clear definitions. even the W3schools site does not greatly help, and does not appear to list for each element whether it is an inline or block element by default, which seems quite an omission.

In the end I found some helpful posts on it here and here which cleared it up for me, and explained why my simple example of a <span> in a <div> would not centre vertically with inline-block and vertical-align:middle!

Note regarding the use of vertical-align, a typical gotcha on this is if you have a horizontal group of buttons/combos and attempt to use top/bottom margins to try to centre them vertically, you may wonder why you do not get the expected behaviour as the margins do not appear to be properly honoured. This is a classic case for using display:inline-block and vertical-align:middle on all the controls.
Primefaces note:- the Primefaces commandButton components are set to  display:inline-block by Primefaces, using the internal jQuery ui-button class.

No Comments »

June 9th, 2010
5:06 pm
Centre text and other items e.g. on a Primefaces command button

Posted under HTML
Tags , , , , ,

Update

This post originally used display:inline-block and vertical-align:middle thinking mistakenly that these were part of the fix for the problem.
See here for a more complete understanding of it.
The modified CSS below works fine just by removing the padding and setting the font.

Taking the Primefaces commandButton as an example, the label is embedded in a span:-

<button attr1=value attr2=value…>
<span>Submit</span
</button>

The button has many attributes which are not relevant to this discussion.
However, as the span is an inline element, it does not have a top/bottom margin, width or height and using text-align:center; in css has no effect.

The default Primefaces button has fixed padding for the label, which works fine by default but which is a pain when you change the size of either the button or the text.

The following rules remove the padding and set the desired font correctly to centre the text for the Primefaces commnadButton:-

.ss-textbutton {
height:20px;
width:52px;
}
.ss-textbutton > .ui-button-text {
font-size:90%;
font-weight: bold;
padding:0px;
}

This CSS is activated when the class ss-textbutton is passed to the styleClass attribute of the commandButton tag.
This example declares a 52 x 20 button. It then targets the <span> within the button using ss-textbutton > ui-button-text, as the <span> in the commandButton has the ui-button-text class. It does the following to the <span>:-

  • sets a font size and weight
  • removes all the padding, so that the centring works correctly

In this example, I have deliberately not changed all buttons globally. The Primefaces documentation explains how to use the classes  ui-button, ui-button-text and ui-button-text-only to skin all buttons globally if this is desired.

This now allows us to resize our button, change the font size and the text, and still have the label nicely centred. We don’t have to mess around with tweaking the padding and other attributes in every case, which is a whole lot simpler and more modular.

No Comments »