Reference Manual for Gracelets - 2.0.0.SP2SourceForge.net Logo
2.18 - Tutorial : Writing Facelet Components
Inside a Gracelet Component Library you can also define Facelet handlers.


Example Component Handler

If you want to instantiate a certain already existing component, but you would like to manipulate it once its created and/or populated, or specify attribute auto wiring, you can do so with a ComponentHandler.

With a ComponentHandler you must specify the component you want to instantiate. You can pass a String which will be interpreted as a component-name defined in a faces-config.xml. You can pass a component defined in the same library. Or you can pass a closure which will return a UIComponent instance.

For instance, one of the optional libraries available is the MetaWidgetComponentLibrary, defined as follows:

Toggle Line Numbers
1 package org.ponder.gracelets.libraries.metawidget 
2  
3 namespace = "http://metawidget.org/faces/html" 
4  
5 div = ComponentHandler(type: "org.metawidget.HtmlMetawidget") { cmp -> 
6     cmp.attributes.rendererType = "div" 
7 } 
8  
9 table = ComponentHandler(type: "org.metawidget.HtmlMetawidget") { cmp -> 
10     cmp.attributes.rendererType = "table" 
11 } 
Above we simply say that when the 'div' tag is called on this library, it should create an instance of 'org.metawidget.HtmlMetawidget', and then once created it should set the 'rendererType' attribute to 'div'. We do the same thing with the 'table' tag, except we specify the table renderer instead of the div one.


Example Tag Handler

One of the main attractions for facelets is the ability to use source files that are templates or parts of pages and that can be reused. In a Gracelet Component Library, it is as easy as creating a gracelet tag to do the same without the need for artifacts (a taglib.xml).

For instance, in the main Gracelets Component Library that comes packaged with gracelets, there is a form tag that is really a tag handler, its purpose is to make sure that the conversation id is propogated, inherent to the form.

This is done as follows:
Toggle Line Numbers
1 form = TagHandler { ctx -> 
2         h.form(ctx.attmap) { 
3             xh.input(type: "hidden", value: { conversation.id }, name: "conversationId") 
4             u.insert() 
5         } 
6     } 
As can be seen you can start defining the tag just like in a gracelets view script, no need to declare the common tag library namespaces. And you can do template inserting so that it works just like a user tag source file.

If we used this then we would get the following results (before facelets sends it to the browser):
Toggle Line Numbers
1 g.form { 
2         print "Enter something: " 
3         h.inputText() 
4 } 
Toggle Line Numbers
1 <form id="j_id23:j_id31:j_id32" name="j_id23:j_id31:j_id32" method="post" action="manual%2Fcurrent_version%2Fchapters%2Ftutorial%2Fwriting_lib_facelets.jsf" enctype="application/x-www-form-urlencoded"> 
2  
3 <input type="hidden" name="j_id23:j_id31:j_id32" value="j_id23:j_id31:j_id32"> 
4 <input type="hidden" value="509" name="conversationId">Enter something: <input type="text" name="j_id23:j_id31:j_id32:j_id35"> 
5 </form> 

The Super Tag Handler

Sometimes it would be nice to use the tag name as some type of indicator, and then build something off this indicator. With a 'proxy' tag you can do just that. You can define as many components as you want in a library, but if you define a 'proxy' tag inside the same library it will 'catch' all tags that do not exist. You will be provided with the name of the tag being used via a special attribute so that you can use that for processing the tag.

The following code shows how this is being done with the wicket component library that comes with the optional wicket extension:

Toggle Line Numbers
1 package gracelets.api.extension.wicket 
2  
3 namespace = "http://wicket.apache.org/gracelets" 
4 alias = "wicket" 
5  
6 proxy = TagHandler { ctx -> 
7     if (ctx.attmap.value) { 
8         def atts = new LinkedHashMap(ctx.atthtml) 
9         atts["wicket:id"] = atts.remove("value") 
10         xh."${ctx.attmap['gracelet.TagName']}"(atts) { u.insert() } 
11     } else { 
12         xh."wicket:${ctx.attmap['gracelet.TagName']}" { u.insert() } 
13     } 
14 } 
As can be seen above this special tag must be called 'proxy'. Inside that you can get the special attribute called 'gracelet.TagName' which will return the name of the tag called on this library but that did not exist. Here we use this so that when a developer makes a Wicket Gracelet Page as a wicket template then he can easily use tag calls instead of having to escape the tags since a ':' in a tag name is not pretty when writing gracelets scripts (i.e., form("wicket:id": "someid")). The following example and the output it generates will demonstrate this (taken from the Guest Book example):

Toggle Line Numbers
1 wicket = ns."http://wicket.apache.org/gracelets" 
2  
3 xh.html("xmlns:wicket": "http://wicket.apache.org/", showDocType: false) { 
4     xh.style { 
5         print "textarea { background-color: rgb(220,220,220); }" 
6     } 
7     wicket.form("commentForm") { 
8         print "Please add your comment here:" 
9         p { wicket.textarea ("text", rows: 10, cols: 75) { print "This is a comment" } } 
10         input(type: "submit", value: "Submit") 
11     } 
12     wicket.span("comments") { 
13         p { 
14             h.outputText("Hello World") 
15             wicket.span("date") { print "1/1/2004" } 
16             wicket.span("text") { print "Comment text goes here" } 
17         } 
18     } 
19     wicket.remove { 
20         p { print "1/1/2004"; br(); print "More comment text here." } 
21     } 
22 } 
Toggle Line Numbers
1 <?xml version="1.0"?> 
2 <style>textarea { background-color: rgb(220,220,220); }</style><form>commentFormPlease add your comment here:<p><textarea rows="10" cols="75">textThis is a comment</textarea></p><input type="submit" value="Submit"/></form><span>comments<p>Hello World<span>date1/1/2004</span><span>textComment text goes here</span></p></span><remove><p>1/1/2004<br/>More comment text here.</p></remove>