Animesh's Blog Exploring Web

Monday Sep 24, 2007

DesignTime-TechNote

Steps Involved in adding designtime for a new component.

Step 1. Adding designtime classes

-  DesignInfo class
-  Bean Info class
-  DesignTime rendeder class
-  entry in faces faces-config file for DesignTime renderer class

Step 2.  Modifying resource and layer.xml files to add the component in palette

An entry needs to be added in layer.xml to view the component on palette.
layer.xml file is located at:
woodstock/ide-plugins/netbeans/woodstock-suite/components/src/org/netbeans/modules/visualweb/woodstock/webui/jsf/designtime

Example: Masthead component entry in layer.xml:
<attr name="WoodstockMasthead.comp_palette_item/WoodstockVersionPage.comp_palette_item" boolvalue="true"/>
and
<file name="WoodstockMasthead.comp_palette_item" url="resources/WoodstockMasthead.comp_palette_item"/>

Create a file "Woodstock+component name+.comp_palette_item" and add it to
woodstock/ide-plugins/netbeans/woodstock-suite/components/src/org/netbeans/modules/visualweb/
woodstock/webui/jsf/designtime/resources

"Woodstock+component name+.comp_palette_item.xml" should have following entries:

<?xml version="1.0" encoding="UTF-8"?>

<palette_item version="1.0">
  <component classname="com.sun.webui.jsf.component.+component name+" type="visual" />
  <!--<icon16 urlvalue="nbres:/com/sun/webui/jsf/component/+component name+_C16.png" />
  <icon32 urlvalue="nbres:/com/sun/webui/jsf/component/+component name+_C32.png" />-->
  <description localizing-bundle="org.netbeans.modules.visualweb.woodstock.webui.jsf.designtime.resources.Bundle"
               display-name-key="NAME_com-sun-webui-jsf-component-+component name+"
               tooltip-key="HINT_com-sun-webui-jsf-component-+component name+"
               help-key="projrave_ui_elements_palette_wdstk-jsf1.2_alarm"/>// this can be modified once the help text is ready
</palette_item>
All the resorce keys needs to be added in Bundle.properties file.
If you do not have icon images for the component then you can comment out that section.

Step 3: Update Project Woodstock Component in NetBeans Visual Web Pack

Install Procedure (Taken from http://wiki.java.net/bin/view/Javatools/InstallingWoodstockComponentsInNetBeans)

1. Set JAVA_HOME to jdk5's installed path

2. Install the Netbeans6.0 development build http://bits.netbeans.org/netbeans/6.0/.

3. Check out a version of the Project Woodstock tree(cvs->woodstock). Currently, only the main trunk of the Woodstock tree has been tested so other branches may not work. There should not be any space in between the checked out path like C:\Program Files\ or C:\Documents and Settings. Sometimes it creates problem while building the project.So Checkout project woodstock in a path where spaces can be avoided.

4. In NetBeans6?, Goto File-> Open Project Now goto the path where you have checked out woodstock and open "woodstock/ide-plugins/netbeans/woodstock-suite" project.

5. Set woodstock-suite as the main project(File-> Set as main project). Now build the project(build->Build Main project). Here you will get some annotation error's, but this will not affect the build.

6. After building the project woodstock suite. Go to the Projects Window and execute "Create NBMs" (Rightclick on "woodstock suite"-> click "create NBMs")from the context menu.

7. Now a directory called updates will be created(woodstock/ide-plugins/netbeans/woodstock-suite/build/updates) This has two generated NBMs files in the woodstock suite build directory.("woodstock/ide-plugins/netbeans/woodstock-suite/build/updates/*.nbms". )

8. Execute the project : Run->Run Main Project which will run another instance of the IDE using a different userdir

9. Goto Tools->Plugins->Downloaded Tab->Add Plugins in the new netbeans IDE. NetBeans6? has a new Plugin installation dialog.

10. Browse to location of built NBMs(woodstock/ide-plugins/netbeans/woodstock-suite/build/updates/*.nbms) and use multi-select to add both of them. Two selected modules should appear in the left pane.

11. Then Press "Install" and follow the instructions

12. Click on finish and now restart the IDE(two options will be there 1.restart now,2. Restart later, select option1 it will restart the ide automatically)

13. Now in the new IDE goto Tools->Plugins to check that the new modules were installed. On the "Settings" tab, select "View->NetBeans Modules". Switch to "Installed" tab and search for "project woodstock". Check that the installed version is correct.

14. Create a webapplication in the new IDE. The palette in the new ide contains the updated components.

==============================================================
DesignTime Implementation:

Adding BeanInfo class:

BeanInfo class needs to be placed under webui/src/designtime/com/sun/webui/jsf/component folder.
This class extends BeanInfoBase class of component.
This class can be used to achieve some specific design-time behavior.
For example to add inline editable functionality to label component.

public class LabelBeanInfo extends LabelBeanInfoBase {

    public LabelBeanInfo() {
        super();
        this.getBeanDescriptor().setValue(
            Constants.BeanDescriptor.INLINE_EDITABLE_PROPERTIES,
            new String[] { "*text://span://label" }); // NOI18N
    }

}

Adding DesignInfo class:

DesignInfo class needs to be placed under webui/src/designtime/com/sun/webui/jsf/component folder.
This class extends AbstractDesignInfo class. Which finally implements designInfo interface.
Here, one can specify the components designtime behavior. For example If vesrsionPage component can not accept
child then accept child method of DesignInfo class will return false.

public boolean acceptChild(DesignBean parentBean, DesignBean childBean, Class childClass) {
        return false;
}

Adding DesignTimeRenderer Class:

It is also possible to overlay a special design-time renderer on top of the normal runtime renderer.
For some components its needed to define DesigntimeRendere to achieve design-time specific behavior. For example,
when a component is dropped for first time in visual designer you may want to put some shadow text and also some
style attribute. This can be achieved using design time renderer class.
Steps to create a design-time renderer class:

1.Create a DesignTimeRenderer, which delegates to the normal runtime Renderer.
2. Add an entry to DesignTimeRenderer to reference the design-time faces-config file.

Design-time renderer will be executed during desing time only; it will not be executed at runtime.

faces-config file:

<renderer>

<component-family>com.sun.webui.jsf.ContentPageTitle</component-family>

<renderer-type>com.sun.webui.jsf.ContentPageTitleDesignTime</renderer-type>

<renderer-class>com.sun.webui.jsf.renderkit.html.ContentPageTitleDesignTimeRenderer</renderer-class>

</renderer> 

    
Code to achieve shadow-text and style for contentPage component:

protected String getShadowText(UIComponent component) {
        return DesignMessageUtil.getMessage(PanelLayoutDesignTimeRenderer.class, "contentPage.label");
    }
    
    public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
        if (component.getChildCount() == 0) {
            ResponseWriter writer = context.getResponseWriter();
            writer.startElement("div", component);
            String id = component.getId();
            writer.writeAttribute("id", id, "id"); //NOI18N
            
            // Calculate CSS height and width style settings
            
            StringBuffer sb = new StringBuffer();
            String style = (String) component.getAttributes().get("style");
           if ((style != null) && (style.length() > 0)) {
                sb.append(style);
                
            }
            if (style == null || style.indexOf("width:") == -1) {
                sb.append("width: 128px; "); // NOI18N
                
            }
            if (style == null || style.indexOf("height:") == -1) {
               
                    sb.append("height: 128px; "); // NOI18N
                    
               
            }
         
            sb.append(style);
            sb.append("; -rave-layout: grid"); // NOI18N
          
            writer.writeAttribute("style", sb.toString(), null); //NOI18N
            sb.setLength(0);
            
            // Calculate CSS style classes
            String styleClass = (String) component.getAttributes().get("styleClass");
            if ((styleClass != null) && (styleClass.length() > 0)) {
                sb.append(styleClass);
                sb.append(" ");
            }
            
            sb.append(UNINITITIALIZED_STYLE_CLASS);
            sb.append(" ");
            sb.append(BORDER_STYLE_CLASS);
            writer.writeAttribute("class", sb.toString(), null); // NOI18
                        
            writer.writeText(getShadowText(component), null);
            writer.endElement("div");
            
            return;
        }
        
        super.encodeBegin(context, component);
    }
    





Thursday Sep 20, 2007

Alert Alert Component:

Alert component enables developers to display an inline alert message at the top of the rendered HTML page. Inline alert messages permit users to correct problems or proceed with their work without having to dismiss a window and navigate to a new location.

The alert component includes an icon, a summary message, and an optional detail message. The icon shown is determined by the type attribute, which must be set to information, success, warning, error or one of the developer define types. Alert supports a set of Indicators which enables to define custom types and associated images in addition with default types.

Indicators:

Use <code>Indicator<code> class to create Indicator objects for any component which needs Indicator.
Indicator object contains an image component a type and a sort value. "type" identifies an Indicator. It is the same as the value given to the Alarm  "severity" property or to the Alert "type" property. An Indicator object can be constructed by calling any Indicator constructors. <code> Indicator(String imageKey, String type, int sortValue) </code> or <code> Indicator(UIComponent imageComponent, String type,  int sortValue) </code>.

Using an Alert component:

An alert component can be written in a page like:
<webuijsf:alert id="msg1" type="information" summary="Patch Installed Successfully" detail="Patch 9997-01 was successfully installed on host alpha, beta and zed." />

An example showing the use of developer define types using Indicators

Example listed below makes a use of Indicator to add a custom type to the default set of indicators.
<webuijsf:alert id="alert1" indicators="#{AlertBean.customIndicator}" type="myType" summary="Summary Text" />

Indicators attribute of alert component is binded with getCustomIndicator().  This method gets the list of default indicator first using
Alert.getDefaultIndicators() and then adds another indicator to the list. This way, now alert support set of default indicators plus the additional
indicator(s) defined by developer in backing bean.

AlertBackingBean.java

 AlertBackingBean {
...
public List getCustomIndicator() {

FacesContext context = FacesContext.getCurrentInstance();
UIComponent comp = context.getViewRoot().findComponent("form1:alert1");
Alert alert = (Alert) comp;

Indicator indicator = new Indicator("ALARM_CRITICAL_SMALL", "myType", 600);

List lst = Alert.getDefaultIndicators();
lst.add(indicator);

return lst;
}
...
}
Updating Alert attributes client side:

Update client-side alert properties using the getProps and setProps functions:

This example shows how to toggle the visible state of an alert client side using the getProps and setProps functions. When the user clicks the radio button, the alert is either shown or hidden.
<webuijsf:radioButton id="rb1" name="rb1" label="Toggle Alert Visible" onClick="toggleVisible()"/>
<webuijsf:alert id="alert1" type="information" summary="#{AlertBean.summary}" />

<webuijsf:script>
function toggleVisible() {
var domNode = document.getElementById("form1:alert1"); // Get alert
return domNode.setProps({visible: !domNode.getProps().visible}); // Toggle visible state
}
</webuijsf:script>

Asynchronously update button using refresh function:

This example shows how to asynchronously update an alert using the refresh function. When the user clicks on the radio button, the alert is asynchronously updated with new data.
<webuijsf:radioButton id="rb1" name="rb1" label="Refresh Alert" onClick="refreshAlert()"/>
<webuijsf:alert id="alert1" type="information" summary="#{AlertBean.summary}" />
<webuijsf:script>
    function refreshAlert() {
        var domNode = document.getElementById("form1:alert1"); // Get alert
        return domNode.refresh(); // Asynchronously refresh alert
    }
</webuijsf:script>

Note that the refresh function can optionally take a list of elements to execute. Thus, a comma-separated list of ids can be provided to update components server-side: refresh("form1:id1,form2:id2,..."). When no parameter is given, the refresh function acts as a reset. That is, the component will be redrawn using values set server-side, but not updated.

Saturday Aug 04, 2007

Recently, a new component named "Bubble" is added in woodstock component list. Bubble component looks similar to a popup help window which appears on certain mouse interaction to a particular screen element. This component can be used for providing detailed information to the user when user hover on certain screen element.
Basic Structure:
Title : The title appears in title bar area.
Remove Control: Appears to the right of the bubble title bar.
Content Area: The main text of the bubble help.
Basic Features:
-"How to close" behavior can be controlled by developer.
- component always position itself under browser boundary.
- positioning can also be controlled by developer.
- delay before opening the bubble can also be controlled by developer, default is 0.5 sec.
- any component can be used for content area.
- component can be refreshed asynchronously.
How to use:
Component exposes two javascript functions (open(event) and close()) to open and close the bubble component.
These functions can be used as follows:
onMouseOver="document.getElementById(bubble component id).open(event);" onMouseOut="document.getElementById(bubble component id).close();"
Example:
Bubble Component can be defined in a jsp page as:
<webuijsf:bubble id="bubble" title="Bubble Help Title"> <webuijsf:staticText text="some help Text" /> </webuijsf:bubble>
Target component: A hyperlink can be used as a target component, "onmouseover" will open the bubble and "onmouseout" will close the bubble component.
<webuijsf:hyperlink id="link1" text="open bubble component" onMouseOver="document.getElementById(bubble component id).open(event);" onMouseOut="document.getElementById(bubble component id).close();" />
Screenshot - Bubble component:


Component offers several other features too. For more details please visit:https://woodstock.dev.java.net

Tuesday Jul 17, 2007

Progressbar uses AJAX to dynamically update the progress, this makes it difficult to access by assistive technologies like screen reader. We can support Firefox's implementation for progressbar (ajax enabled components) A11Y which makes it accessible for keyboard and assistive technologies such as screen readers too. Assistive technology support requires Firefox 1.5+ and specially marked-up content which uses namespaced attributes to describe each widget. Widget should provide ARIA (Accessibility Rich Internet Applications) attributes for example: "role" should be one of the supported widget type (like progressbar) and other supported property attributes.

Role and supported properties for progressbar:
role: progressbar
properties: valuenow, valuemax, valuemin
There are few important things that needs to be considered when implementing A11Y support to ajax enabled component:
-Live regions in the content
-Types of widgets
-States and property information

Currently we have identified two different approaches to implement A11Y support to progressbar (AJAX enabled components)
-Using XHTML 1.1
-Using HTML 4

Using XHTML:
===========
In XHTML 1.1, we can add accessible roles and states by declaring the appropriate namespaced attributes.
Example:
xmlns:wairole="http://www.w3.org/2005/01/wai-rdf/GUIRoleTaxonomy#"
xmlns:waistate="http://www.w3.org/2005/07/aaa">
And then we can add the supported role and properties to the div for bottomText (ProgressBar)
waistate:valuenow="0" waistate:valuemin="0" waistate:valuemax="100">

Now we can dynamically update the above div to announce progress updates by updating "valuenow" attribute
domNode.setAttributeNS("http://www.w3.org/2005/07/aaa",
"valuenow",progress);
Using HTML 4:
============
HTML documents do not support namespaces, so the required accessibility role and state metadata can not be included directly in these documents. But we can define the role and states as keywords in the class attribute and these can be parsed using an ECMAScript library to parse them and copying them into the appropriate namespaces. There is an ECMAScript library available to do this (enable.js) at http://developer.mozilla.org/en/docs/Accessible_DHTML
Example:
We simply need to add role and states in class attribute to the div for bottomText (ProgressBar) "axs progressbar valuemin-0 valuemax-100 valuenow-0" "axs" class signals to the ECMAScript compatibility library that this element defines additional role and state information. "progressbar valuemin-0 valuemax-100 valuenow-0" are the role and state information for the progressbar.
After adding styleClasses we can use setAttrNS to update "valuenow" attribute.
var e = this.bottomTextContainer;
if(e != null && setAttrNS)
setAttrNS(e,"http://www.w3.org/2005/07/aaa", "valuenow", this.progress);
For more details:
http://www.w3.org/WAI/PF/adaptable/HTML4/embedding-20061212.html
http://developer.mozilla.org/en/docs/Accessible_DHTML