Blog Archives

May 9th, 2011
4:24 pm
Installing MantisBT for Issue Tracking

Posted under Hosting
Tags , ,

I was looking into a suitable tool for software issue/bug tracking. The following were my main goals:-

  1. I wanted access via the internet from anywhere as a prime requirement, so I needed a hosted application.
  2. I did not want to be forced to get custom hosting for it, and already use cpanel hosting extensively as it is readily available and cheap, so ideally I would need a PHP application which was easy to run and install on cpanel.
  3. I wanted Open source/community software if possible.
  4. I did not have much in the way of a feature shopping list, but ideally wanted a stable and feature rich package that could also be customised as required. My initial requirements would be fairly basic but I wanted a package that would accommodate growing needs in the future, such as multiuser features for a software development team, reporting etc.

 

Possible Contenders

  • Jira is very feature rich and is used by a number of major Java projects such as Java.net, Primefaces etc. However it needs Java hosting as it is a Java application, so for me that knocked it out of the frame.
  • Bugzilla was also a possible contender, being written in Perl it might run under cpanel, but having seen a post attempting this it looked a nightmare to install, and it was not clear that it would work under cpanel without elevated permissions which I did not have. I wanted a simple solution not another project!
  • Finally, I looked at MantisBT, and this appeared to tick all the boxes. It is highly feature rich, stable, and easy to install under cpanel. It lacks some nice to have features, such as text formatting for the issues – all the issue text and notes in Mantis are plain text, whereas with other packages, rich text is used so text formatting such as bold, underline etc. can be used. However, the one vital thing I needed was easy/automatic hyperlinking of URLs in the issue text, and fortunately Mantis does this very well and fully automatically. The hyperlinking is basic, just giving you the actual URL as the hyperlink description, but it works perfectly well. Also, whilst nice formatting is icing on the cake, it is important to remember that this is after all an issue/bug reporting tool for use by developers, so sexy formatting is not a primary concern. As I have used it further, I have been very impressed with the feature set. It allows full relationship definition between issues, supports multiple/hierachical projects, and supports both categories for issues and tagging in blog fashion. It also has full notification email support and this may be configured as desired. It is highly customisable, and has many more features than I would need initially.

 

MantisBT Installation and Configuration Notes

The documentation is very comprehensive and installation is straightforward. Basically it is a case of unzipping the kit on the server, creating a MySQL database and associated accounts via cpanel, and editing config_inc.php to put the database/login and other details in. Note the following points :-

  1. You need to pull the database settings out of config_inc.php, merge them with config_inc.php.sample, and create a new version of config_inc.php.
  2. I changed the file upload method from DATABASE to FILE. After doing so, I tested file upload and it was fine. You can leave the upload path blank in the config file. If you then set the upload folder for a project to ‘uploads/xxx/’ this will go to <mantis install directory>/uploads/xxx/, exactly as you would expect.
  3. As long as you set the folder permissions to 755 for the top level mantis folder you will be fine, the install and the file upload will both work. Prior to copying the sample config file, I got file path errors on a file upload (when it was set to the default of DATABASE), but after setting it to FILE it all worked fine.
  4. Note that email notifications work fine, but when testing, you DON’T get notified of your own changes by default (see config file), so you need to make changes using a second account to test email notify. Also, the default for a user is not to receive emails on a status change, so you need to change this as well.

 

Issue Tag Plugin

By default, Mantis supports tagging but does not make the feature very visible – you cannot see tags on the issue list screen by default. An excellent Tag plugin is available here. Having installed this, you can configure a column to display the tags and place it where you like (full instructions on the plugin web site). I placed the tags next to the categories. The plugin gives Mantis comprehensive tag support; you can see all the tags in the issue lists and the tags are clickable links. I highly recommend this plugin and having used it for a while I would not use Mantis without it.

No Comments »

April 12th, 2011
3:28 pm
Action, Listener and Validator Retargeting in a JSF composite component

Posted under JSF
Tags , , , ,

Update 6/7/2011

There appear to be major issues with the design of retargeting when using it in nested composite components – it fundamentally does not work. See this JSF JIRA issue here for details on this. There is quite a robust debate in the comments on the post as to whether to deprecate and redesign retargeting completely, but it looks like that will not happen.

Original Post

This is very much an undocumented feature of JSF 2, but it is possible for the action method for a command component such as a button or link to be passed in to the CC by its client.

You might think that you can just pass in a method expression string as an attribute and use that attribute within the CC on the action attribute of a button, but this fails as there is more that needs to go on behind the scenes. To make it work, you use the targets= attribute when declaring the action attribute on the CCs interface using composite:attribute – note that the attribute in the CC interface must be called action.

This is discussed in a comment (by Cay Horstmann no less) in this StackOverflow post here.

Note that according to the link here from the above post, you can also retarget actionListeners, validators and valueChangeListeners in the same way. In these cases, the attribute name must be called actionListener, validator or valueChangeListener respectively in the same manner as is done with action above. Check the link out for full details – its not exactly clear on its own but it is easier to understand once you have the concepts from Cay Horstmann’s post above.

No Comments »

April 12th, 2011
2:21 pm
Composite Components–Best Practice

Posted under JSF
Tags , , , ,

Update

The original post below mentioned at the beginning #{cc.attrs.clientId}. Whilst this does work and is mentioned on the net, the correct form is #{cc.clientId}. I have amended accordingly.

Original Post

This post here is an IBM Developerworks post on CC best practice. Some comments/observations follow:-

  1. Wrap a cc in a div (NOT a panelgroup) and give it id=“#{cc.attrs.clientId }” “#{cc.clientId }” to give it the ID given to the actual composite. Note that if you use a div, it will NOT be given the CC’s Nameingcontainer prefix (and hence will not have the “double ID” issue whereby it prefixes the ID you specify with the naming container prefix again).
  2. You cannot specify an h:panelGroup inside a CC without an ID, or the resulting div is not rendered on the page at all.
  3. The id= and rendered= are both ‘standard’ attributes of a CC that you can use by virtue of the fact that a CC is a jsf component – you don’t need to roll your own ‘display=’ attribute for example. This is helpful, as otherwise you would need to wrap a CC in a div in order to give it the CC naming container ID as in 1/, but you would also need to wrap it additionally in an actual h:panelGroup in order to roll your own display= ‘rendered’ style attribute. This may very well be the reason why you get an illegal argument exception if you try to specify your own rendered= attribute on a CC (as per this Mantis issue).
  4. cc.id is a built in reference for the CC’s declared ID without any naming container prefixes. cc.clientId is the full monty with all the prefixes. These are analagous to component.id and component.clientId which can be used for any JSF component. Sadly I have not seen any full documentation for the cc or component built in objects.

The second part of the IBM Developerworks article is here. It details how to add Ajax behaviour to a CC, and in particular how to add Ajax behaviour to a component inside a CC from outside. This is useful for less complex CCs, and partners with the other features like retargeting which allows you to pass a listener to a CC which is attached to a component inside the CC.

For more complex CCs, I tend to take a different approach, as follows:-

  • I code a controller class in Java for use with the CC, and pass it in as an attribute of the CC (typically controller=). Any behaviour of components inside the CC such as Ajax and listeners are all handled by this controller bean.
  • The controller bean is injected by CDI as an @dependent bean, and is typically injected into the page bean which acts as controller for the page. In this way, the lifecycle of the controller is tied to that of its containing bean, which is clear and exactly as it should be.
  • As the controller is a dependent bean, CDI allows it to be generic and to use parameterised types (you can only do this for a dependent bean). For example, I have my own breadcrumb control CC (see here) which has its own controller class. This accepts a list of crumbs, where a crumb is a parameterised type for the class.
  • A page may have multiple instances of such a CC, in which case it just injects multiple controllers, one per CC that it manages.
  • In order to provide event handling, I take a simple approach. A controller just has an event interface which it calls out to in order to pass on any relevant events such as listener or action events. Typically, these will mimic the interface for a listener or action and just pass it on. I generally add an additional argument to the start of all such calls, containing a reference to the controller itself (i.e. the controller passes this in the argument). This is useful in cases where for example the containing page bean itself implements the event interface and handles the events, as where there are multiple components/controllers on a page this argument can be used to determine which one the event was for.
  • A key concept with this technique, which works better for more complex cases, is that I am not just exposing internal component behaviour of components in the CC to the outside as you might using JSF retargeting for example. Rather, I am using the controller to provide its own abstraction of the internal behaviour and to provide an external interface which reflects its overall function. In other words, I can map the internal behaviour to the external interface in any way I choose, which gives me much greater control and design flexibility.
  • Another approach would be to use a JSF CC Backing Component, as detailed in Core Javaserver Faces on p373. This allows Java behaviour to be added to a CC transparently to the CC’s clients. However, it does involve using some of the JSF internal interfaces that would also be used to develop full blown custom components. In that sense it provides a halfway house to a full custom component implementation. I have deliberately not used this approach in my use cases – the ‘controller’ approach I have outlined is simple and clear, and easy to develop. The controller is not hidden, being declared as a dependent by a calling backing bean, and being passed in to the CC on the facelet page. I feel that in my use cases the visibility, clear lifecycle control, and use of a separate controller instance per component on the page are a benefit and keep things clear and simple.  In design pattern terms, JSF uses the MVC pattern. The JSF components form the view, and my controllers and page beans form the controller. It could be said that a backing component for a CC is part of the view rather than part of the controller, as it uses internal JSF interfaces used by JSF components to implement the view part of the pattern.

No Comments »

March 25th, 2011
6:43 pm
Creating Javascript Objects using new – the pros and cons

Posted under Javascript
Tags , ,

There are a number of pros and cons regarding this practice, and they are debated on StackOverflow here. A w3schools tutorial on it may be found here.

I have used this e.g. here, following the lead of the Primefaces dialog.js. A downside is that your code fails if you forget the new and just call the function instead. However, this can be detected and an error thrown as per the StackOverflow post. In my case, the thrown error was not easily detected so I elected to pop an alert as well.

I do not discuss the issue further here – just follow the links and you will find plenty of information on it.

No Comments »

March 25th, 2011
6:42 pm
Implementing confirmation dialogs with Primefaces p:dialog

Posted under JSF
Tags , , , , ,

Update 7/3/2012

Primefaces p:ajax partial refreshes can also be blocked by returning false to the onclick event.  In this case, an If statement needs to be used, so that “return false” is done to block the refresh, but no return at all is done to allow the refresh. This allows the Primefaces ppr logic to execute – returning true explicitly in the onclick actually stops the ppr/ajax logic from executing at all:-

onclick="if (!confirmAction(Arguments)) {return false};"

The nice feature of this method is that it works in an identical fashion for both full page and partial refreshes, so that is is not necessary to mess with logic which couples both the onstart and onclick attributes based on the ajax setting.

The downside is that as before we are adding bare Javascript logic into an element attribute. In defence, this situation has already been forced on us by the JSF/Primefaces design – the interface already requires us to return false to block a request, so whilst this might be distasteful from a purist Javascript point of view, it is a fact of life we have to live with.

 

Original Post

Confirmation dialogs are typically used when for example a form is being edited and a navigation to another page is attempted.

Traditionally, this might be done by using the Javascript confirm function which pops a browser dialog, and returns true or false depending on the user choice. However, modern web apps shy away from using browser popup dialogs. Their styling is browser dependant and they cannot be restyled. A modern app will use custom styled dialogs with features like fade in/out and lightboxing to give a more subtle appearance and to allow the dialog to be displayed in-page to avoid popup blocking problems. Also, component libraries such as Primefaces allow custom themes and theme switching for an application, which would therefore allow their own custom dialogs to be dynamically restyled.

The fundamental complication when using such a custom dialog is that unlike the built-in Javascript confirm function, it does not operate synchronously. This immediately raises major issues when using it to confirm navigation, as it cannot be used inline in a navigation confirmation event on a button or link.  This post looks at how to get around this issue and use a Primefaces p:dialog to implement a confirmation dialog.

 

Allowing or blocking navigation attempts

The first point to address is how we can actually allow or block a navigation attempt on a Primefaces/JSF button or link. There are two options available, which are straightforward and applicable to all buttons and links:-

  • For full page refreshes, returning false from the onclick event aborts the navigation. This is a standard JSF feature which is described here. It is also mentioned in Core Javaserver Faces Edition III on p573, although it must be said that it is rather hidden near the back of the book and hard to dig out.
  • For Primefaces p:ajax partial refreshes, returning false from the onstart event aborts the ajax call.

Note that in both cases, it is important to prefix the function call with the return statement, otherwise the function return value is not correctly returned by the event call. For example, using the traditional Javascript confirm function:-

  • onclick=”return confirm(‘Pending edits will be cancelled, do you want to continue?’);”
  • onstart=”return confirm(‘Pending edits will be cancelled, do you want to continue?’);”

When applying a default case, it is also possible to just return true or false without calling anything, e.g. using onclick=”return true;”

 

Using the p:dialog  to allow/block the navigation

This is a little tricky to get right, but actually turns out to be fairly straightforward, and in particular, we can still initiate the whole process from a single function call in the onclick or onstart event as above. The idea makes use of the fact that we can issue a soft click on an HTML (or in this case jQuery) element using the .click() call. The steps are as follows :-

  1. The user clicks on a button, which causes our own Javascript confirm(elementId) function to be called by say the onstart event. Importantly, the clientId of the target element which was clicked is passed and stored, as it may be needed later.
  2. if edit mode is inactive, the function just returns true to allow the action.
  3. If edit mode is active, then the function sets an internal confirmInProgress flag and shows the confirmation p:dialog via its widget show() function. The function then returns false to (initially) block the Ajax action.
  4. When the dialog is displayed and the user clicks No, a Javascript cancelAction() function is called which hides the dialog and clears the confirmInProgress flag. The Ajax action is not then performed.
  5. When the dialog is displayed and the user clicks Yes, a Javascript performAction() function is called which hides the dialog and forces a second (software) click on the button, using the previously stored elementId. This results in confirm() being called a second time.
  6. When confirm() is called the second time via the software click (because the user clicked yes to confirm), we can detect this as the confirmInProgress flag will be set. The function then clears the confirmInProgress flag and returns true to allow the Ajax action to proceed.

 

Implementation Points

  • When implementing this, my confirmation dialog is a facelets custom tag. Within the tag, I create a Javascript object (whose precise name is passed by the caller) which contains the above logic and manages the confirmation process.
  • The Javascript object is created via the new keyword – see my other post here with links on this topic.
  • I then pass the confirm function call used on this object as a text attribute value to any tags, buttons or links that need to implement confirmation. For a high level tag I would pass it as an onNavigate attribute, and within the tag it would be passed on to any links or buttons to which it applies.
  • In order to do the software click, the clientId of the element that was clicked is passed to the confirm function and stored on the Javascript object. To do this, the confirm function call is passed as a MessageFormat style string with a placeholder which will take the clientId, as this must be added by the target button typically via a reference to #{component.clientId}. In this way the final target could add additional parameters if required, but is nicely decoupled from the actual Javascript call. The only interface contract is the placeholder parameter index, and the fact that a boolean must be returned to permit/deny navigation. I typically add MessageFormat.format (in addition to string concatenation) as custom EL java functions declared in a tag library – in the example below, these functions have the el: prefix.
  • In our case, the actual element clientId is a constant string as far as the Javascript call is concerned, so it must have single quotes added. These are added in the context of the target element – they are not passed in the MessageFormat string. This way, the caller does not decide whether or not a parameter is a Javascript String – this is decided in the target element environment. For example, if an additional argument such as a JavaScript reference such as this was passed in the target element environment, it would not need to be quoted, and the caller’s MessageFormat string containing the Javascript call would not have to know. This maintains good decoupling.
  • The Javascript object also has an internal confirmMode property which indicates whether confirmation mode is actually on, i.e. if edit mode is active. If not, it just permits everything as per the above logic steps. This JS property would normally be set from an edit mode bean property on the actual edit form which triggers the confirm. To do this, I pass the JS property reference in to the tag handling the edit form. and it calls a standard utility tag to issue an inline script statement to assign the property reference from the bean. This assignment needs to be within a div which is updated by ajax when the edit mode changes, to ensure the property is reassigned.

 

Example Code Fragments

Facelets Page declaring the Confirmation Dialog

<util2:confirmActionDialog tagId="confirmDialog" widgetVar="confirmWidget" />           

<cheep:campaignTreeBrowser id="campaignTreeBrowser" idPath="#{form}" currentNodeChange="#{form}:pnlCampaignDetail"
                           currentNodeChangeOnComplete="ss_PanelExpand(widgetVarPnlCampaignDetail)"
                           controller="#{campaignsPage.campaignTreeBrowser}" edit="#{true}"
                           onNavigate="confirmWidget.confirm({0})"/>
                                                             
<cheep:campaignDetailPanel tagId="pnlCampaignDetail" idPath="#{form}" editModeFlag="confirmWidget.confirmMode"
                           controller="#{campaignsPage.campaignDetailPanel}"/>

confirmActionDialog.xhtml custom tag

<!DOCTYPE HTML>
<html xmlns="http://www.w3c.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core"   
xmlns:p="http://primefaces.prime.com.tr/ui"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:fn="http://java.sun.com/jsp/jstl/functions"
xmlns:util="http://java.sun.com/jsf/composite/uk.co.salientsoft/util">

<ui:composition>
    <h:outputScript library="uk.co.salientsoft/util" name="confirmActionDialog.js" target="head"/>
       
    <script type="text/javascript">#{widgetVar} = new uk.co.salientsoft.ConfirmActionDialog();</script>   
   
    <p:confirmDialog id="#{tagId}" widgetVar="#{widgetVar}.dialogWidget" styleClass="ss-confirmaction-dialog"
                message="#{empty confirmMessage ? mainMsg.confirmEditCancel : confirmMessage}"
                showEffect="fade" hideEffect="fade"
                header="#{empty confirmTitle ? mainMsg.confirmEditCancelTitle : confirmTitle}" severity="alert">
               
        <util:iconTextButton id="cmdAbort"  image="ui-icon ui-icon-close"
                label="#{mainMsg.optionNo}" title="#{mainMsg.optionTitleNo}" onclick="#{widgetVar}.cancelAction()" />                                                    
       
        <util:iconTextButton id="cmdConfirm"  image="ui-icon ui-icon-check" 
                label="#{mainMsg.optionYes}" title="#{mainMsg.optionTitleYes}" onclick="#{widgetVar}.performAction()" />
    </p:confirmDialog>
</ui:composition>
</html>

Setting the EditMode flag in the campaignDetailPanel edit form

<!– Set the edit mode state in the specified Javascript flag used by the navigation confirmation dialog when in edit mode –>
<util2:setScriptVar name="#{editModeFlag}" value="#{controller.editMode}" defaultValue="false" />

Custom tag util2:setScriptVar

<!DOCTYPE HTML>
<html xmlns="http://www.w3c.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:c="http://java.sun.com/jsp/jstl/core"   
xmlns:el="http://salientsoft.co.uk/EL">

    <ui:composition>   
        <!– Set the specified Javascript variable/property from the given EL expression –>
        <c:if test="#{not empty name}">
            <script type="text/javascript">#{name} = #{empty value ? defaultValue : value};</script>
        </c:if>
    </ui:composition>
</html>

Code within a link which adds the actual onstart event (this example is taken from a composite component)

<p:commandLink id="link" ajax="#{cc.attrs.ajax}" async="#{cc.attrs.async}" disabled="#{cc.attrs.disabled}"
         action="#{cc.attrs.controller.iconButtonAction(cc.attrs.eventHandler, cc.attrs.actionMethod,
                              cc.attrs.actionParam, cc.attrs.passController, cc.attrs.passActionParam)}"
         actionListener="#{cc.attrs.controller.iconButtonActionListener}"
         process="#{cc.attrs.process}" update="#{cc.attrs.update}" immediate="#{cc.attrs.immediate}"
         href="#{cc.attrs.href}" title="#{cc.attrs.title}" tabindex="#{cc.attrs.tabIndex}"
        onstart="return #{empty cc.attrs.onNavigate ? ‘true’ : el:format1(cc.attrs.onNavigate, el:concat3(‘\”, component.clientId, ‘\”))}"
         oncomplete="#{cc.attrs.oncomplete}" onsuccess="#{cc.attrs.onsuccess}" onerror="#{cc.attrs.onerror}">
…   

</p:commandLink>

Javascript object ConfirmActionDialog.js

/*
* This object handles the logic for confirming Primefaces Ajax actions via a confirmation dialog.
* It is typically used to pop a confirmation when in edit mode on a form and e.g. a navigation link/button has been clicked.
* A navigation link/button should call confirm() in its onstart Ajax event. The following then happens:-
*
* 1/ if EditMode is inactive, confirm() just returns true to allow the action.
* 2/ If EditMode is active, then confirm() pops the confirm dialog and returns false to (initially) block the Ajax action.
* 3/ When the dialog is popped and the user clicks No, hide the dialog and return to the idle state (Ajax action not performed).
* 4/ When the dialog is popped and the user clicks Yes, we hide the dialog and force a software click on the Ajax link/button.
* 5/ When confirm() is called the second time via the software click (because the user clicked yes to confirm),
*    return to the idle state and return true to allow the Ajax action.
*/

var uk=uk||{}; uk.co=uk.co||{}; uk.co.salientsoft=uk.co.salientsoft||{};
uk.co.salientsoft.ConfirmActionDialog = function () {
    this.confirmInProgress = false; //initialise to the idle state
    this.confirmMode = false; //set no confirmation needed initially (e.g. not in edit mode)
};

uk.co.salientsoft.ConfirmActionDialog.prototype.show = function() {
    this.dialogWidget.show();
};

uk.co.salientsoft.ConfirmActionDialog.prototype.hide = function() {
    this.dialogWidget.hide();
};

uk.co.salientsoft.ConfirmActionDialog.prototype.confirm = function(elementId) {
    if (this.confirmMode && !this.confirmInProgress) {
        var escapedId = ‘#’ + elementId.replace(/:/g, ‘\\3A ‘);
        this.element = jQuery(escapedId);
        this.dialogWidget.show();
        this.confirmInProgress = true;
        return false; //first time in, cancel the Primefaces Ajax action until confirmed
    }
    else {
        /*
         * Either we are not in confirm mode (e.g. edit mode is off),
         * or we are in confirm mode and this is the second time in, called as a result of a confirm.
         * Either way we allow the Primefaces Ajax action, and return to the idle state.
         */
        this.confirmInProgress = false;
        return true;
    }
};

uk.co.salientsoft.ConfirmActionDialog.prototype.performAction = function() {  
    this.dialogWidget.hide();
    this.element.click(); //This will cause confirm() to be called again; this time the Ajax action will be allowed.
};

uk.co.salientsoft.ConfirmActionDialog.prototype.cancelAction = function() {  
    this.dialogWidget.hide();
    this.confirmInProgress = false; //we will not be performing the Ajax action, so return to the idle state
};

No Comments »

March 23rd, 2011
4:08 pm
Mapping Browser Keyboard events to Element Clicks

Posted under Javascript
Tags , , ,

I wanted to do this as a way to add keyboard accelerators, mainly for enter and escape when doing editing etc.

The code was already implemented to be driven from mouse click events, so causing keyboard events to soft click particular target buttons for save and cancel was convenient as this was then completely isolated from the rest of the code, which only had to be concerned with being button driven.

I found the following issues during the implementation:-

A keypress event was fine for trapping Enter, but it did not trap escape correctly. For escape, I needed to drive from the keyup event.

My enter event was bubbling up and causing unwanted navigation. I initially tried cancelling bubbling and propagation as detailed here on Quirksmode.org:-

function doSomething(e)
{
    if (!e) var e = window.event;
    e.cancelBubble = true;
    if (e.stopPropagation) e.stopPropagation();
}

This involves catering for browser differences , as shown, as the Microsoft/IE model uses cancelBubble, whereas the W3C model uses stopPropagation. In my case, this did not solve the issue.

My simple solution was for the event handler to return false when it had trapped and handled a keyclick such as enter, and to return true otherwise. Returning false blocked any further action on the event, and was also a standard mechanism. I did not bottom out the actual problem in my case, but this solved it completely.

When implementing the solution, I used the following technique:-

  1. An object literal was created which did a reverse map from all the key codes I might want to trap, to a mnemonic name for them (such as enter, escape, leftArrow).
  2. My event handler call accepts a keyActions object literal argument where the names are the above mnemonics, and the values are the element IDs which need to be clicked when the matching key code is detected.
  3. In the event handler, I reverse lookup the key code to the mnemonic, and then look up the element Id in the passed object literal using the mnemonic.
  4. If I find an element Id, I click it and return false. If I do not find one, I return true as I am not trapping that key.
  5. I also try a lookup on the passed keyActions object using the raw key code. This means that the caller can either use a mnemonic or a key code to specify what key is handled.
  6. The event handler therefore has very little code, and does not need any loops – it just does 2 associative lookups to get the target element to click.
  7. As an additional feature, I allow an idPath key/value to be passed in keyActions. If this is present, any element value which is not prefixed with ‘#’ will be prefixed with the id path, to simplify the call site where a number of elements with a common ID prefix are specified. Elements already prefixed with ‘#’ are left untouched.

This technique would also work well when implementing global key handling attached to the <body> tag. In this case, it may be desirable to switch the global handling depending on what is open on the page. For example, there might be an in-page detail form which is opened in-place and client side using a Primefaces p:panel. In this case, the keyActions object could be switched when the detail panel is opened, and switched back when it is closed.

Another useful trick if the complexity warrants it could be to implement a stack such that detail panels on the page push their own keyActions onto the stack, perhaps inheriting the global ones and modifying them as required. When a detail level is closed, it can just pop the stack and does not need to know about the higher levels of actions on the page. To assist with this, it would be useful to be able to clone the previous level actions when adding a new level. Prototypes could be used for this, but they need constructor functions etc. and do not map well to our simple case which just uses JSON like object literals. The jQuery extend method could be a good choice for this, and is detailed here on StackOverflow by none other than Mr jQuery himself, John Resig (!)

The following example code fragment from a utility object illustrates the idea:-

var uk=uk||{}; uk.co=uk.co||{}; uk.co.salientsoft=uk.co.salientsoft||{};
uk.co.salientsoft.util= {
    clearElement: function(elementId) {
        jQuery(uk.co.salientsoft.util.escapeId(elementId)).val(”);
    },
    escapeId: function(elementId) {
        //a value tests true if it is non-null, non-blank, not NAN, not undefined, and not false
        var escapedId = (elementId) ? ((elementId.charAt(0) == ‘#’ ? ” : ‘#’)  + elementId.replace(/:/g, ‘\\3A ‘)) : ”;
        return escapedId;
    },
    keyCodeNames: {
        /*
         * Common list of keycodes, allowing reverse lookup of name from code.
         * Derived from: http://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes
         * This only includes the common function/special keys which should be browser independant.
         */
        8:’backspace’,
        9:’tab’,
        13:’enter’,
        16:’shift’,
        17:’ctrl’,
        18:’alt’,
        27:’escape’,
        33:’pageUp’,
        34:’pageDown’,
        35:’end’,
        36:’home’,
        37:’leftArrow’,
        38:’upArrow’,
        39:’rightArrow’,
        40:’downArrow’,
        45:’insert’,
        46:’delete’,
        112:’f1′,
        113:’f2′,
        114:’f3′,
        115:’f4′,
        116:’f5′,
        117:’f6′,
        118:’f7′,
        119:’f8′,
        120:’f9′,
        121:’f10′,
        122:’f11′,
        123:’f12’       
    },
    clickOnKey: function(event, keyActions) {
        /*
         * This is a keyup/keydown/keypress event handler.
         * keyActions is an object literal containing key mnemonics for the keys, and target elements for the values.
         * As well as mnemonics, raw key code numbers can be used.
         * A special object literal key, idPath, may be used to specify a default ID prefix.
         * If present, it is applied to all element IDs which are not prefixed with a ‘#’. 
         * Examples:-
         *    onkeypress="return uk.co.salientsoft.util.clickOnKey(event, {enter:’frm1:cmdSaveNew:link’});"
         *    onkeyup="return uk.co.salientsoft.util.clickOnKey(event, {escape:’cmdCancelNew:link’, idPath:’frm1:’});"
         *
         * NOTE – escape handling does not work on a keypress event.
         * The event is detected, but the click fails to do anything.
         * onkeyup should be used for escape, as this does not suffer from the problem.
         */
        var keycode = (event.keyCode ? event.keyCode : event.which);
       
        /*
         * Try to fetch the target element id from the passed keyActions assuming a string key code name was used, e.g. ‘enter’
         * If this fails, try a lookup based on the raw key code.
         * Doing it this way avoids looping.
         */       
        var actionElement = keyActions[uk.co.salientsoft.util.keyCodeNames[keycode]];
        if (actionElement == null) {
            actionElement = keyActions[keycode];
        }       
       
        /* If found a target for the event keycode, click it
         * and return false to stop any propagation, else return true
         */
        if (actionElement != null) {
            if (actionElement.charAt(0) != ‘#’ && keyActions.idPath != null) {
                actionElement = keyActions.idPath + actionElement;
            }
            jQuery(uk.co.salientsoft.util.escapeId(actionElement)).click();
            return false;
        }
        return true;
    }
};

No Comments »

March 23rd, 2011
3:24 pm
Java Generics–Class literals as run time type tokens

Posted under Java
Tags , , , ,

This post refers to the section on page 16 of the Generics tutorial document by Gilad Bracha.

The example here uses the Cojen dynamic bytecode generation library in order to create custom sort comparators. The advantage of Cojen is that you end up with a fully compiled comparator and therefore do not incur the performance hit of reflective code. Furthermore, comparators generated by Cojen can be cached in a map so that they are only generated once. This particular example borrows some code originally used for Icefaces table sorting, which I adapted for use with Primefaces. Whilst Primefaces does have its own table sorting, I had some issues with it. I wanted visibility of the current sort column and direction, and I wanted control over the sorting – I wanted to reapply the sort to a table when rows were added to it from another table, so that it was always maintained in order. Furthermore, I wanted to maintain the current sort column and direction that had been selected by the user via the column headers when applying the sort when new rows were added. As I had trodden this route before for Icefaces, it was straightforward to move the code over and incorporate it into a standard table controller class which I was already developing.

One issue which I had not previously bottomed out in the Icefaces version was making the code fully generic and fully eliminating all the generic warnings when using a class literal as a run time type token. With Cojen, you call a static forClass method on its BeanComparator to construct a comparator, passing in the class and the comparator ordering details:-

if (beanComparator == null) {
    beanComparator = BeanComparator.forClass(rowClass).orderBy(key);               
    comparatorMap.put(key, beanComparator);
}   

In my first Icefaces attempt, I pulled the first row out of the current row list for the table, and passed that to Cojen to create the class. The problem with this was that I could not do it generically this way. My second attempt, with the Primefaces version, passed the class in to an init method generically. As this tied up all the generics loose ends correctly, everything was happy and the class was recognised as having the correct parameterised type. The cost of this was the need to pass it explicitly as an argument to an init method (or a setter), but this was simple and made the parameterised type clear and explicit. This is the correct approach and one that I will use from now on.

The following code fragments illustrate the mechanism:-

Call Site


    private @Inject TableCtrl<Person, RowMetadata> personTable;

        personTable.init(Person.class, RowMetadata.class, this);

 

TableCtrlImpl.java

@Dependent
public class TableCtrlImpl<C, D extends RowMetadata> implements Serializable, TableCtrl<C, D>, Iterable<C> {

    private Class<C> rowClass;

    private Map<String, BeanComparator<C>> comparatorMap = new HashMap<String, BeanComparator<C>>();

@Override public void init(Class<C> rowClass, Class<D> rowMetadataClass, TableCtrlEvent<C, D> tableCtrlEvent) {       
    rowMeta = new RowMetaMap<C, D>();
    this.rowClass = rowClass;
    this.rowMetadataClass = rowMetadataClass;
    this.tableCtrlEvent = tableCtrlEvent;
}

    @Override public void sort() {
        if (sortColumn != null && !rows.isEmpty()) {
            String key = (sortAscending ? “” : “-“) + sortColumn;
            BeanComparator<C> beanComparator = comparatorMap.get(key);
            if (beanComparator == null) {
                beanComparator = BeanComparator.forClass(rowClass).orderBy(key);               
                comparatorMap.put(key, beanComparator);
            }
           
            Collections.sort(rows, beanComparator);
        }
    }

No Comments »

March 22nd, 2011
8:27 pm
Using the Browser Resize Event in jQuery

Posted under JSF
Tags , , , ,

jQuery ties into this event in a browser independant way. The following code fragment illustrates the use of this. Note tha following points:-

  • Different browsers implement resize differently. Most fire continual events during the resize, but some browsers (e.g. I believe older versions of Firefox) just fire the resize at the end of the drag. You therefore cannot predict how often and when the resize is called.
  • You need to place the code in the body section – I placed it in the head initially and it was never called.
  • When referring to a function defined in the head section as I have here, you need to prefix the call with “document.” otherwise the target function appears out of scope. The example assumes that yourFunctionName is a Javascript function defined elsewhere, e.g. in the header section of the page.

 

        <script type=”text/javascript”>
                /*
                 * This script block executes the target function on a resize.
                 * Note that jQuery has a browser independant means to hook into the event.
                 */
                jQuery(window).resize(function() {
                //alert(‘resize called’);
                document.yourFunctionName(args);
            });
        </script>

No Comments »

March 22nd, 2011
8:11 pm
Fixing Primefaces scrolling table header width issues using jQuery

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

This has been very much an ongoing chestnut with Primefaces, mainly due to the tricks you have to use in order to get fixed table column headers and a scrolling table. Primefaces does this with a pair of tables – one for the header row and another for the data. The problems which often arise are mismatching columns between the header and the data, incorrectly sized table header above the column headers, and an incorrectly sized header row which does not appear to size properly dynamically when scrollbars are present/absent.

These issues can often be fixed, but it does appear that there is no overall silver bullet which makes everything work in every use case. The best approach I have found is to have a selection of approaches to try, and to apply the appropriate ones to solve problems which arise in particular use cases. The following details the different approaches I have used in various cases to solve width and alignment problems.

The following commented code sample shows how to use jQuery to correct table header width and column header width problems for scrolling tables. These problems are typically triggered by the dynamic appearance/removal of scrollbars, which will depend on table height and row count. Note that the function described, ss_FixTableHeaderWidth, would either be called in an inline script block placed immediately after a table definition in a facelets page (for a static table) or would be triggered as part of an Ajax call (for a dynamically rendered Ajax table). The example shows the static case. Note the following points about the code:-

  • The code may be found in the repository here.
  • The jQuery selectors should be optimised for performance. In general, ID selectors are the most efficient, so  narrow down with an ID selector first if you can (as below). Element selectors are also efficient, but classes can be really slow depending on what the browser supports – jQuery may end up doing a full DOM tree scan for every class selector, which is highly undesirable!. To avoid this below, I have prefixed class selectors with an element type which then makes use of the faster element searching, e.g. div.ui-scrollable-datatable.
  • Avoid duplicating selector searches where possible – in the example below a reuse them where I can, by using previous selector results as the context for subsequent lower level selectors, for example jQuery(‘div.ui-scrollable-datatable-container’, mainDiv) makes use of the jQuery result mainDiv from a previous selector when selecting its descendant scrollable container div.
  • You need to keep track of the difference between DOM elements returned by some calls, and jQuery objects which can be returned by others. You can always wrap a DOM element with a jQuery object using jQuery(element), but this is not always necessary. Avoid the overhead of doing it when you already have a jQuery object as it is redundant. The jQuery documentation makes all this clear.
  • The jQuery online docs are available here.  You cannot directly download the docs from the jQuery site, but it does link to some unofficial PDF downloads. However, the best and most searchable option seems to be an unofficial windows help file/CHM version download linked from StackOverflow (not fully up to date but still very useful). This is available here.
  • The RH header column size is set to auto to accommodate header row size changes, the idea being that this RH column will expand to fill the row, and the browser will not mess with other column sizes. Note that the column widths are just a guide to the browser and it is free to mess with them. This can be really awkward as we rely on the header table and data table being rendered exactly the same way to line up. This auto approach seems to work.
  • Firefox (3.6 and 4) has a problem whereby when setting an element width (in this case with jQuery), the actual value set is often 1px less than the requested value (particularly a problem when setting header table width). This can easily be seen by reading back the element width immediately after setting it. The fix I use for this is to do all width setting in a function (ss_setWidth) which checks the width afterwards and calculates the value of the mismatch. If there is a mismatch, the mismatch is then added to the width to set, and the element width is set a second time. This function is safe to use for all browsers.

 

Function definition, placed in page header section

    <script type=”text/javascript”>
    //<![CDATA[

        function ss_FixTableHeaderWidth(formId, tableId) {
           
            /*
             *Fix incorrect table header width due to scrollbars
             */
           
            var fullTableId = ‘#’ + formId + ‘\\3A’ + tableId;
            var topHeader = jQuery(fullTableId + ‘ > div.ui-datatable-header’);
            var mainDiv = jQuery(fullTableId + ‘ > div.ui-scrollable-datatable’);
            var headerTable = jQuery(‘table.ui-scrollable-datatable-header’, mainDiv);
            var dataContainer = jQuery(‘div.ui-scrollable-datatable-container’, mainDiv);           
            var dataTable = jQuery(‘table.ui-scrollable-datatable-body’, dataContainer);           
            var lastColumnHeader = jQuery(‘thead > tr:eq(0) > th:last’, headerTable);

/*           
            alert (‘TableId=’+fullTableId + ‘\n’ +
                   ‘topHeader=’+topHeader.attr(‘class’) + ‘\n’ +
                   ‘mainDiv=’+mainDiv.attr(‘class’) + ‘\n’ +
                   ‘headerTable=’+headerTable.attr(‘class’) + ‘\n’ +
                   ‘dataContainer=’+dataContainer.attr(‘class’) + ‘\n’ +
                   ‘dataTable=’+dataTable.attr(‘class’) + ‘\n’ +
                   ‘lastColumnHeader=’+topHeader.attr(‘class’));
*/           
            /*
             * Set the RH header column width to auto to prevent header table width adjustments
             *  from messing up column alignments
             */
            lastColumnHeader.css(‘width’, ‘auto’);

            /*
             * For some themes (pepper-grinder, overcast, ui-lightness), the width is incorrectly set for a scroll bar
             * even when there isn’t one. Detect whether scroll bars are actually present and fix the width if required.
             */
            if (dataContainer.outerHeight() >= dataContainer.get(0).scrollHeight) {
                //alert(‘Scroll bars not present’);
                //dataContainer.width(dataTable.outerWidth());
                ss_setWidth(dataContainer, dataTable.outerWidth());
            }       

            //Now set the width of the column headers table correctly and then finally the table header to match.
            var newHeaderTableWidth = headerTable.width() + dataContainer.outerWidth() – headerTable.outerWidth();
            var newTopHeaderWidth = topHeader.width() + dataContainer.outerWidth() – topHeader.outerWidth();

            //headerTable.width(newHeaderTableWidth);
            ss_setWidth(headerTable, newHeaderTableWidth);
            //topHeader.width(newTopHeaderWidth);
            ss_setWidth(topHeader, newTopHeaderWidth);
        }
       
        function ss_setWidth(element, value) {
           /*
            * This function overcomes an issue with Firefox (3.6 and 4), whereby the actual width set for an element
            * (particularly the header table) is sometimes less (typically 1px less) than the passed width to be set.
            * We read back the width after setting it, and if it differs from what we set,
            * we adjust our original value by the mismatch and set the width again.
            */           
            element.width(value);
            mismatch = value – element.width();
            if (mismatch != 0) {
                //alert(‘mismatch=’+mismatch+’ fixed’)
                element.width(value + mismatch);
            }
        }       
    //]]>
    </script>

Function call, placed inline immediately following table

<p:dataTable …>

</p:dataTable>
<script type=”text/javascript”>ss_FixTableHeaderWidth(‘frmTest’, ‘tblTable’);</script>

Iterating columns to set the width for each one individually

The following code sample uses the jQuery .each loop to iterate the header columns and set the width of each one to its matching data column (along with setting the table/row widths correctly). This sounds ideal for solving the header problems, but in practice it did not work well. The main issue is that jQuery reported a different value for the header column widths to that reported by the browser (via Firebug). The values were out by 1px, which caused an incremental mismatch in the column alignment as you go left to right. This approach was therefore abandoned in favour of just setting the RH header column size to auto to accommodate row size changes, as explained above. However, I reproduce the code here as it is a useful example of how to iterate a returned  jQuery object collection from a selector.

Function definition, column iteration version

    <script type=”text/javascript”>
    //<![CDATA[

        function ss_FixTableHeaderWidth(formId, tableId) {

            /*
             *Fix incorrect table header width due to scrollbars
             */
            
            var fullTableId = ‘#’ + formId + ‘\\3A’ + tableId;
            var topHeader = jQuery(fullTableId + ‘ > div.ui-datatable-header’);
            var mainDiv = jQuery(fullTableId + ‘ > div.ui-scrollable-datatable’);
            var headerTable = jQuery(‘table.ui-scrollable-datatable-header’, mainDiv);
            var dataContainer = jQuery(‘div.ui-scrollable-datatable-container’, mainDiv);           
            var dataTable = jQuery(‘table.ui-scrollable-datatable-body’, dataContainer);           
           
            /*
             * For some themes (pepper-grinder, overcast, ui-lightness), the width is incorrectly set for a scroll bar
             * even when there isn’t one. Detect whether scroll bars are actually present and fix the width if required.
             */
            if (dataContainer.outerHeight() >= dataContainer.get(0).scrollHeight) {
                //alert(‘Scroll bars not present’);
                //dataContainer.width(dataTable.outerWidth());
                ss_setWidth(dataContainer, dataTable.outerWidth());
            }                       

            /*
             * Now iterate the columns with a jQuery each loop and set the header column width
             * to be the same as its corresponding data column width.
             * This is for illustration – the idea has been abandoned, as I found that Javascript/jQuery
             * reports a different value for the header widths to firebug on the final rendered page (out by 1px).
             * This causes an increasing mismatch between data columns and header columns as you go from left to right.
             * The column widths are only a suggestion and the browser may modify them anyway.
             * Therefore the final version, in SortTable.xhtml just sets the RH column width to auto
             * to take up the slack when the row width is changed, and leaves the others alone.
             * This appears to work much better.
             * However the iteration technique here is a useful working jQuery example.
             */
            var columnHeaders = jQuery(‘thead > tr:eq(0) > th’, headerTable);
            var firstRowCells = jQuery(‘tbody > tr:eq(0) > td’, dataTable);
            var columnCount = columnHeaders.size()
           
            columnHeaders.each(function(idx){
                    var columnHeader = jQuery(this);
                    if (idx < columnCount – 1) {
                       
                        var firstRowCell = jQuery(firstRowCells.get(idx));
/*
                        alert(‘idx=’+idx+’\n’+
                              ‘header width=’+columnHeader.width()+’\n’ +
                              ‘header csswidth=’+columnHeader.css(‘width’)+’\n’ +
                              ‘header innerWidth=’+columnHeader.innerWidth()+’\n’ +
                              ‘header outerWidth=’+columnHeader.outerWidth()+’\n’ +
                              ‘data width=’+firstRowCell.width()+’\n’ +
                              ‘data csswidth=’+firstRowCell.css(‘width’)+’\n’ +
                              ‘data innerWidth=’+firstRowCell.innerWidth()+’\n’ +
                              ‘data outerWidth=’+firstRowCell.outerWidth());
*/
                        var newWidth = columnHeader.width() + firstRowCell.outerWidth() – columnHeader.outerWidth();
                        //alert(‘idx=’+idx+’,width=’+columnHeader.width()+’, newWidth=’+newWidth);
                        //columnHeader.width(newWidth);
                        ss_setWidth(columnHeader, newWidth);
                    }
                    else {
                        columnHeader.css(‘width’, ‘auto’);
                    }
              });

            //Now set the width of the column headers table correctly and then finally the table header to match.
            var newHeaderTableWidth = headerTable.width() + dataContainer.outerWidth() – headerTable.outerWidth();
            var newTopHeaderWidth = topHeader.width() + dataContainer.outerWidth() – topHeader.outerWidth();

            //headerTable.width(newHeaderTableWidth);
            ss_setWidth(headerTable, newHeaderTableWidth);

            //topHeader.width(newTopHeaderWidth);
            ss_setWidth(topHeader, newTopHeaderWidth);
        }
       
        function ss_setWidth(element, value) {
            /*
             * This function overcomes an issue with Firefox (3.6 and 4), whereby the actual width set for an element
             * (particularly the header table) is sometimes less (typically 1px less) than the passed width to be set.
             * We read back the width after setting it, and if it differs from what we set,
             * we adjust our original value by the mismatch and set the width again.
             */                       
            element.width(value);
            mismatch = value – element.width();
            if (mismatch != 0) {
                //alert(‘mismatch=’+mismatch+’ fixed’)
                element.width(value + mismatch);
            }
        }       
    //]]>
    </script>

No Comments »

March 8th, 2011
6:47 pm
JSF – changing input component values in a value change listener

Posted under JSF
Tags , , , , ,

My requirement on this one was to have some linked logic between select checkboxes on table rows and a ‘select all’ checkbox in the column header. Checking ‘select all’ should check all the row boxes. Then, unchecking one or more of the row boxes should uncheck ‘select all’ as the rows are no longer all checked.

Initially I had decided to get a whole test form working without Ajax, then apply the desired Ajax to all of it consistently. I had previously hit event timing issues due to mixing Ajax and HTTP submits on the same form. This gave rise to strange behaviour such as old queued events seeming to fire from nowhere, and events containing null arguments in method expressions. The basic wisdom on this is don’t mix Ajax and traditional HTTP submits on the same form – bad things will happen! I therefore decided to get the code logic working first with plain submits, by adding “onclick=’submit();’” to the checkboxes to force submits temporarily. The idea behind this was to avoid getting a mix of problems due to Ajax and problems due to other coding bugs, by eliminating the other coding bugs first.

The approach when doing this kind of thing is typically to set the components to immediate=”true” and call FacesContext.getCurrentInstance().renderResponse(); at the end of the value change listener to force an immediate rendering.

The problem I hit however, was that although I was correctly setting bean values for other checkboxes from the listener, the values were not being read again prior to renderResponse(),so the new values were not being displayed on the page. This is in fact standard behaviour. The way to update the values being rendered is to call setValue()  on the actual UIInput Component as well as writing the backing bean. To do this you need to get at the component instance, and the best way to achieve this is to use the binding attribute in the JSF page. For example, the following code fragments could be used in the JSF page and the managed bean:-

 

JSF Page

<h:selectBooleanCheckbox value=”#{mainBean.selectedB}”
                         valueChangeListener=”#{mainBean.selectedListenerB}”
                         binding=”#{mainBean.selectBoxBBinding}”
                         id=”chkSelectB” immediate=”true” onclick=”submit();”>
</h:selectBooleanCheckbox>

 

Managed Bean

private UIInput selectBoxBBinding;

public UIInput getSelectBoxBBinding() {
    return selectBoxBBinding;
}
public void setSelectBoxBBinding(UIInput selectBoxBBinding) {
    this.selectBoxBBinding = selectBoxBBinding;
}

 

Value Change Listener

public void selectedListenerA(ValueChangeEvent event) {
    boolean newValue = (Boolean)event.getNewValue();
    setSelectedA(newValue);

   //SelectedB is set to the same value as selectedA
    setSelectedB(newValue);
    selectBoxBBinding.setValue(newValue);
    FacesContext.getCurrentInstance().renderResponse();
}

This causes the new value to be displayed in the updated checkbox.  Binding to a component allows access to a number of other properties and methods as well, so gives a lot of flexibility. However, in most normal cases straightforward value binding is enough.

 

Using Ajax to achieve the same result

Ironically, if I had used Ajax on this issue, I would not have hit the problem. When Ajax is used, setting the new values in the managed bean is enough to allow them to be displayed directly on screen. The following JSF fragment shows how to use Ajax in check box SelectA in order to directly update check box SelectB without using a form submit. execute=@this causes the server side processing for SelectA to be performed (@this means the current component and is the default). render=”chkSelectB” causes the rendering to be peformed for SelectB, which displays the new value. Both execute and render take a space delimited list of client Ids, or special keywords such as @this, @form, @all, @non etc. The Ids can be prefixed with “:” to force Id scanning from the root where there are naming container issues etc. I am not covering any of this here. 

<h:outputText value=”Select Box A”/>
    <h:selectBooleanCheckbox value=”#{mainBean.selectedA}”
                             valueChangeListener=”#{mainBean.selectedListenerA}”
                             id=”chkSelectA”>
    <f:ajax execute=”@this” render=”chkSelectB”/>
    </h:selectBooleanCheckbox>
<br/><br/>
<h:outputText value=”Select Box B”/>
    <h:selectBooleanCheckbox value=”#{mainBean.selectedB}”
                             valueChangeListener=”#{mainBean.selectedListenerB}”
                             binding=”#{mainBean.selectBoxBBinding}”
                             id=”chkSelectB”>
    </h:selectBooleanCheckbox>

No Comments »