In a series of five articles I have discussed how boilerplate text elements such as prompts and labels could and should be taken out of pages and centralized in resource bundles. I have explained how resource bundles can be implemented in database tables, how the bundles can be refreshed at run time and how different user groups can be served with different resource bundles. The previous article demonstrated how text properties can be edited at run time, in the context of the application.
The approach discussed for live text editing works fine. However, its current implementation requires specific manipulation – of every individual page. Each page contains a popup component and each component to be edited needs to have an associated showPopupBehavior or even a commandImageLink.
This article outlines a more generic approach that requires virtually no page or component specific preparation. The popup is takes out of the page into a page fragment. This page fragment is included in every page using a single declarative component tag. Via a phaseListener on the f:view tag, the UIComponent tree of every page is programmatically manipulated before being rendered. The manipulation consists of adding showPopupBehavior children to all UIComponents with textual properties.
The manipulation of the UIComponent tree is a fine way to influence the appearance of any JSF application at run time, based for example on meta data that can also be managed at run time. I have made use of this approach on several occasions.
1. Move the popup from the page to a fragment and include the fragment as declarative component
The popup component is copied to a JSFF file:
The popup is subsequently included into PageOne.jspx (and every other JSPX file) through a declarative component:
Note: because the declarative component is a naming container, the reference to the popup in the showPopupBehavior components is changed from just editTextResources to texteditPopup:editTextResources.
2. Run Time manipulation of the UIComponent tree
Define managed beans
Configure f:view component
Implement the phaseListener bean
Implement the UI Component Tree manipulator bean PageProcessorForTextEditing
The page can be in text editing mode (or not). This is determined by a property on the pageProcessorForTextEditing bean. The toggle between textEditing mode and non-textEditing mode is made using a commandLink:
in code this looks like this:
Whenever the commandLink is clicked to enter text editing mode, the page is re-rendered and before rendering takes place, the viewPhaseListenerBean steps in and calls the processPage() method in the pageProcessorForTextEditing bean. This method traverses the UI Component Tree and calls upon a helper method to add the showPopupBehavior listeners.
The method addPopupBehaviorOnUIComponent programmatically creates the equivalent of the <af:showPopupBehavior> component, associated with the text editor popup:
The method componentIsTextEditable verifies whether the component is one that we want a showPopupBehavior added to:
The findClientListenerSet() method inspects a UIComponent and tries to locate its clientlistenerset. If it does not exist, it finds out whether the UIComponent is an ADF Component that supports clientListeners (i.e. exposes a method getClientListeners()). If it does, a new ClientListenerSet is instantiated and set on the component.
Alternative UI facilities for opening the popup text editor
Using a mouseOver – or double click – to trigger the popup works okay, but is a little implicit. The user needs to know what to do. There are ways of implementing more visual, more explicit access points for the user. An example is the context facet:
the little orange square that the user can hover over:
when clicked, the popup editor will open.
This context facet can be added programmatically using this code:
Note that only input components such as inputText and selectOneChoice support the context facet.
Also note that a small modification is required in the populateProperties() method in class TextEditor to recognize the RichContextInfo and ensure that the textual properties are shown for the parent of the context component:
Another UI widget that we can add programmatically to make access to the text editor more explicit is through the use of a commandImageLink:
The code that will add this commandImageLink:
This code is invoked for CommandButton components:
Download the ADF application with the code demonstrated in this article: ADFFacesWithResourceBundle_Step7_DynamicUITreeManipulation.
Other articles in this series: