dominoGuru.com
Your Development & Design Resource
IBM XPages Dojo borderContainer Layout Custom Control
07/31/2012 02:15 PM by Chris Toohey
Extending the Extension Library xe:djBorderContainer, this take on a "Lotus Notes Client frameset" for XPages shows how we can create a reusable layout-type Custom Control that provides an alternative to an OneUI application layout.
Now while I don't hate OneUI themeing for XPages applications, I think it's absolutely critical to the adoption of XPages as an application services platform that we show the ability to serve alternative application UIs lest people unfamiliar with the technologies at play think XPages is OneUI...
Let's kick things off with an overview of the desired end-result:
This wireframe/mockup of the Dojo borderContainer (seen below) shows off a headline layout configuration. Alternately, there's a sidebar option that gives us a more traditional Lotus Notes client frameset-layout.
There are also various configuration options (such as enabling liveSplitters, which allows the user to resize the "frames") which we'll want to support.
The basic setup of an xe:djBorderContainer layout looks like this:
<xe:djBorderContainer>
<xe:djContentPane>
top
</xe:djContentPane>
<xe:djContentPane>
leading
</xe:djContentPane>
<xe:djContentPane>
center
</xe:djContentPane>
<xe:djContentPane>
trailing
</xe:djContentPane>
<xe:djContentPane>
bottom
</xe:djContentPane>
</xe:djBorderContainer>
This is, of course, sans any functional properties. But it should give you an idea of the basic setup:
The xe:djBorderContainer uses xe:djContentPane children controls to act as a container for each "frame". The order I've used here - top, leading, center, trailing, bottom - is more for visual/logical flow and has absolutely nothing to do with function: position of a "frame" has nothing to do with position, but rather the "region" attribute on the generated HTML DIV (which the Dojo library runs with to create the frame/frameset layout).
To make our xc:layout Custom Control as dynamic and configuration-controlled as possible, we'll want to wire as many xe:djBorderContainer and xe:djContentPane properties to the Properties of the Custom Control.
The cool thing about an xe:djBorderContainer is that you can either use the xe:djContentPane as a standard xp:div-like "container" Control, or use the AJAX-driven "scraping" abilities to create an iframe-like container for any content from within the same domain (or cross-domain should you choose to employ an XAgent -- for example -- to interact with an external web service).
Let's take a look at a configured xc:layout first to get an idea of the various options you'll have for populating your "frameset" layout:
<xc:layout>
<xp:this.facets>
<xp:div
xp:key="contentPane_top_bodycontent">
<xp:text tagName="h1" styleClass="heading" value="#{javascript:@DbTitle();}" />
</xp:div>
</xp:this.facets>
<xc:this.borderContainer>
<xc:borderContainer
bC_gutters="true"
bC_liveSplitters="true"
bC_design="sidebar"
bC_parseOnLoad="true"
bC_persist="true">
</xc:borderContainer>
</xc:this.borderContainer>
<xc:this.contentPane_bottom>
<xc:contentPane_bottom
cP_region="bottom"
cP_splitter="true">
</xc:contentPane_bottom>
</xc:this.contentPane_bottom>
<xc:this.contentPane_center>
<xc:contentPane_center
cP_region="center"
cP_splitter="true">
</xc:contentPane_center>
</xc:this.contentPane_center>
<xc:this.contentPane_leading>
<xc:contentPane_leading
cP_region="leading"
cP_splitter="true"
cP_href="navigation.xsp"
cP_extractContent="false"
cP_loadingMessage="Loading
application navigation controls..."
cP_maxSize="350"
cP_minSize="200"
cP_parseOnLoad="true">
</xc:contentPane_leading>
</xc:this.contentPane_leading>
<xc:this.contentPane_top>
<xc:contentPane_top
cP_region="top"
cP_splitter="false">
</xc:contentPane_top>
</xc:this.contentPane_top>
<xc:this.contentPane_trailing>
<xc:contentPane_trailing
cP_region="trailing"
cP_splitter="true"
cP_rendered="false">
</xc:contentPane_trailing>
</xc:this.contentPane_trailing>
</xc:layout>
Here we're using a combination of XPage markup (in the "top" xe:djContentPane), "scraped" XPages (in the "leading" and "center" xe:djContentPanes). We'll also be using a "scraped" download.html Page Design Element for the Demo download. We're also telling the "trailing" xe:djContentPane to not render, again all driven via the configuration of the xc:layout Custom Control.
Now let's take a look at the XPage markup for the xc:layout Custom Control:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view
xmlns:xp="http://www.ibm.com/xsp/core"
xmlns:xe="http://www.ibm.com/xsp/coreex"
dojoParseOnLoad="true"
dojoTheme="true">
<xp:this.resources>
<xp:styleSheet
href="/screen.css" />
<xp:script
src="/screen.js"
clientSide="true">
</xp:script>
</xp:this.resources>
<xe:djBorderContainer
id="djBorderContainer_layout"
design="#{compositeData.borderContainer.bC_design}"
dir="#{compositeData.borderContainer.bC_dir}"
gutters="#{compositeData.borderContainer.bC_gutters}"
liveSplitters="#{compositeData.borderContainer.bC_liveSplitters}"
persist="#{compositeData.borderContainer.bC_persist}"
rendered="#{compositeData.borderContainer.bC_rendered}"
styleClass="#{compositeData.borderContainer.bC_styleClass}"
themeId="${compositeData.borderContainer.bC_themeId}">
<xe:djContentPane
id="djContentPane_top"
dir="#{compositeData.contentPane_top.cP_dir}"
errorMessage="#{compositeData.contentPane_top.cP_errorMessage}"<
/span>
extractContent="#{compositeData.contentPane_top.cP_extractContents}"
href="#{compositeData.contentPane_top.cP_href}"
loadingMessage="#{compositeData.contentPane_top.cP_loadingMessage}"
partialRefresh=