attached mail follows:
<my:columnLayout id="newspaper" border="2px dashed blue" columns="3" title="The Sparky Times">
<h:outputLink ... />
<h:graphicImage ... />
<h:outputText ... />
<h:outputLink ... />
<h:graphicImage ... />
<h:outputText ... />
</my:columnLayout>
ColumnLayout.java
public class ColumnLayout extends TemplateComponentBase implements NamingContainer {
/**
* <p> Constructor for <code>ColumnLayout</code>.</p>
*/
public ColumnLayout() {
super();
setRendererType("org.example.ColumnLayout");
// This is the location of the file that declares the layout
setLayoutDefinitionKey("jsftemplating/columnlayout.jsf");
}
/**
* <p> Return the family for this component.</p>
*/
public String getFamily() {
return "org.example.ColumnLayout";
}
}
ColumnLayoutFactory.java
@UIComponentFactory("my:columnLayout")
public class ColumnLayoutFactory extends ComponentFactoryBase {
public UIComponent create(FacesContext context, LayoutComponent descriptor, UIComponent parent) {
// Create the UIComponent, this must be registered in the
// faces-config.xml file.
UIComponent comp = createComponent(
context, "org.example.ColumnLayout", descriptor, parent);
// Set all the attributes / properties
setOptions(context, descriptor, comp);
// Return the component
return comp;
}
}
faces-config.xml
<component>
<component-type>org.example.ColumnLayout</component-type>
<component-class>org.example.component.ColumnLayout</component-class>
</component>
<render-kit>
<renderer>
<component-family>org.example.ColumnLayout</component-family>
<renderer-type>org.example.ColumnLayout</renderer-type>
<renderer-class>com.sun.jsftemplating.renderer.TemplateRenderer</renderer-class>
</renderer>
</render-kit>
columnLayout.jsf
<!beforeEncode
// Before we start, initialize a request attribute (currentCol) to "0"
setAttribute(key="currentCol" value="0");
// Get the # of columns, default to '2'... normally the default should be
// handled by the component, but we didn't put any code in our component.
setAttribute(key="columns" value="2");
if ($property{columns}) {
setAttribute(key="columns" value="$property{columns}");
}
// Calculate the column width for the css we will write, save in request
// scope variable "colWidth"
my.getColumnWidth(columns="#{columns}", colWidth=>$attribute{colWidth});
/>
// Column around the whole component for easy client-side identification
"<div id="$this{clientId}">
// Provide a place for a facet to replace the title, the contents of the
// <!facet> tag provide the default title layout used if a 'title' facet is
// not supplied.
<!facet name="title">
// Only render the default title if a 'title' property is supplied
<!if $property{title}>
<f:verbatim>
<div id="$this{clientId}_title" class="colTitle"
style="position: absolute; left: 2%; width: 88%;
text-align: center; border: $property{border}">
$property{title}</div>
</f:verbatim>
</if>
</facet>
// Start the first column
<f:verbatim>
<div id="$this{clientId}_column0" class="column"
style="position: absolute; left: 2%; top: 80px;
width: #{colWidth}%; border: $property{border}">
</f:verbatim>
// Loop through all the children of the columnLayout component
<!foreach _child : $this{children}>
// As we loop through the properties, add new columns as appropriate
<!if #{currentCol}<#{col}>
<!beforeEncode
// This calculates the column # before the above 'if' statement
my.getColumnNumber(
max="$attribute{_child-size}",
index="$attribute{_child-index}",
columns="#{columns}",
col=>$attribute{col});
/>
<!encode
// This only executes if the above 'if' statement is 'true'
// Set a new "left" position for css, and update the column #
my.getLeftPosition(columns="#{columns}", col="#{col}",
colPos=>$attribute{left});
setAttribute(key="currentCol" value="#{col}");
/>
// We need to end the previous column and start a new one
<f:verbatim>
</div>
<div id="$this{clientId}_column#{col}" class="column"
style="position: absolute; left: #{left}%; top: 80px;
width: #{colWidth}%; border: $property{border}">
</f:verbatim>
</if>
// This displays the child component we are currently evaluating in the
// "foreach" loop with a <div> around it.
"<div class="colEntry" id="$this{clientId}_entry$attribute{_child-index}">
<component id="#{_child.id}" />
"</div>
</foreach>
// Close the last column
"</div>
"</div>
MyHandlers.java
These handlers use @annotations to eliminate their configuration. Once they are compiled they are directly usable from the templates. Their input and output is converted automatically to the correct Java types and required values inputs are ensured. Multiple inputs and outputs are possible via the named I/O properties -- all accessible via the HandlerContext object that is provided by the framework. This makes it easy to pass data between Java and the template.
public class MyHandlers {
/**
* <p> This handler calculates the column width given the # of columns
* to display on a page. It assumes at most 90% of the page will
* be used to display the columns.</p>
*/
@Handler(id="my.getColumnWidth",
input={
@HandlerInput(name="columns", type=Integer.class, required=true)
},
output={
@HandlerOutput(name="colWidth", type=Integer.class)
})
public static void calculateColumnWidth(HandlerContext context) {
// Get the input.
int numColumns = (Integer) context.getInputValue("columns");
// Determine the width
int colWidth = getColumnWidth(numColumns);
// Set the output.
context.setOutputValue("colWidth", colWidth);
}
/**
* <p> Does the actual column width determination.</p>
*/
private static int getColumnWidth(int numColumns) {
return 90 / numColumns - COL_PADDING;
}
/**
* <p> This handler calculates the column left position given the # of
* columns, the current item number, and the total number of items to
* be displayed. It assumes at most 90% of the page will be used to
* display the columns.</p>
*/
@Handler(id="my.getColumnNumber",
input={
@HandlerInput(name="columns", type=Integer.class, required=true),
@HandlerInput(name="max", type=Integer.class, required=true),
@HandlerInput(name="index", type=Integer.class, required=true)
},
output={
@HandlerOutput(name="col", type=Integer.class)
})
public static void calculateColumn(HandlerContext context) {
int numColumns = (Integer) context.getInputValue("columns");
int idx = (Integer) context.getInputValue("index");
int max = (Integer) context.getInputValue("max");
context.setOutputValue("col", (numColumns * (idx-1)) / max);
}
/**
* <p> This handler calculates the column left position given the # of
* columns, the current item number, and the total number of items to
* be displayed. It assumes at most 90% of the page will be used to
* display the columns.</p>
*/
@Handler(id="my.getLeftPosition",
input={
@HandlerInput(name="columns", type=Integer.class, required=true),
@HandlerInput(name="col", type=Integer.class, required=true)
},
output={
@HandlerOutput(name="colPos", type=Integer.class)
})
public static void calculateColumnPosition(HandlerContext context) {
// Get the input.
int curColumn = (Integer) context.getInputValue("col");
int numColumns = (Integer) context.getInputValue("columns");
int colWidth = getColumnWidth(numColumns);
// Determine the position
int pos = (colWidth + COL_PADDING) * curColumn + COL_PADDING;
// Set the output.
context.setOutputValue("colPos", pos);
}
public static final int COL_PADDING = 2;
}
demo.jsf
"<style type="text/css">#newspaper_entry7 {border: 1px solid green}</style>
"<style type="text/css">.colEntry {background-color: #EEEEEE}</style>
<my:columnLayout id="newspaper" border="2px dashed blue" columns="3" title="The Sparky Times" >
<!facet name="title">
<h:panelGroup>
<h:graphicImage url="https://glassfish-theme.dev.java.net/logo.gif" style="vertical-align: middle; padding-bottom: 15px;"/>
<h:outputText style="font-size: 2em; font-family: Arial; color: blue;" value=" The Sparky Times" />
</h:panelGroup>
</facet>
<h:outputLink value="https://jsftemplating.dev.java.net"><staticText value="JSFTemplating" /></h:outputLink>
"Entry 2
"Entry 3
<h:outputLink value="https://glassfish.dev.java.net"><staticText value="GlassFish" /></h:outputLink>
<h:outputLink value="https://woodstock.dev.java.net"><staticText value="Woodstock" /></h:outputLink>
"Entry 6
<h:outputLink value="http://blogs.sun.com/paulsen"><staticText value="Ken Paulsen's Blog" /></h:outputLink>
"Entry 8
"Entry 9
<h:graphicImage url="https://glassfish-theme.dev.java.net/logo.gif" />
</my:columnLayout>