XPages Calendar Control In A Table

In my last blog entry I showed how it was
possible to build a calendar using a couple of repeat controls and some
CSS but in reality a calendar is more suited to be displayed as a table.
By using a table your calendar will also degrade nicely in older web browsers
so I decided to give it a shot and see if it was possible to do in XPages.

The basic concept is still the same.
I need to know how many days there are in the month and I need to know
what day to start the first calendar entry on. Because I’m using a table
I will also need to complete the last row of table columns with blank entries
so this means I will need another repeat control.

In the CSS version of the calendar I
assigned the first day of each week a slightly different style so that
it would ensure that the row would move down. In a table I will need to
close a table row tag and open a new one. At first I tried to just add
a </xp:tr> and a <xp:tr> tag into the main repeat and set their
‘rendered’ value so that they would only render on the first day of each
week but Domino Designer would not allow me to do this because you cannot
add a ‘rendered’ value to a closing tag, only the opening tag.

To get around this I decided to just
fool the xpages rendering engine to output the closing and reopening table
row tags by using a computed field that is set to send it’s results to
the web browser as html.

A picture named M2

This worked perfectly, before the repeat
control outputs the first table column of the week and closing tag for
the previous table row and then an opening tag for the next table row is
sent to the browser.

The last thing I needed to do was add
an extra repeat to fill out the blank table columns at the end of the last
row and then I needed to close the final table row before closing the entire
table. The maximum number of rows that a calendar might take is 6, this
means that your calendar table must have at least 42 table columns split
over the 6 rows. You already know the number of blanks at the start of
the table and the number of days in the month so subtracting these from
42 will give you the number of blanks at the end of the table.

Of course it’s entirely possible for
a calendar month to only need 4 rows, as was the case in February this
year where the first of the month was a Sunday and the 28th of the month
was a Saturday so we need to check the result of our calculation to remove
any blank rows by subtracting either 14 or 7 as necessary.

A picture named M3

Now we just need to apply a little CSS
just for the table and we have a working calendar control in XPages based
on a table.

A picture named M4

Tagged with: ,
Posted in None

Building an XPages Calendar Custom Control

If you read my blog directly on my site
and not through a RSS reader then you may have seen the nifty calendar
that I wrote in BlogSphere. It’s AJAX based and allows the reader to move
backwards and forwards through the different months to see what other days
have blog entries.

A picture named M2

I wanted to recreate something very
similar in XPages and started looking at a few options. The blogsphere
version is a table which makes sense as it really is tabulated data but
after thinking of a few ways to do it in XPages I decided to move to a
pure CSS generated calendar. Each of the little squares in the calendar
is a simple SPAN and the CSS is used to give them a border, float them
to the left so they all line up after each other and then a surrounding
DIV forces them to wrap around.

The header for the calendar is defined
as simply as



<xp:span styleClass="calHeader">S</xp:span>
<xp:span styleClass="calHeader">M</xp:span>
<xp:span styleClass="calHeader">T</xp:span>
<xp:span styleClass="calHeader">W</xp:span>
<xp:span styleClass="calHeader">T</xp:span>
<xp:span styleClass="calHeader">F</xp:span>
<xp:span styleClass="calHeader">S</xp:span>


The next set of spans are the empty
cells at the start of the calendar. Before I create the empty cells for
the calendar I need to figure out how many there will be so I need a bit
of server side javascript.



viewScope.dispCalYear = @Year(@Now());

viewScope.dispCalMonth = @Month(@Now());
viewScope.daysInMonth = new Date(viewScope.dispCalYear, viewScope.dispCalMonth,
0).getDate();
viewScope.firstDayInMonth = new Date(viewScope.dispCalYear,viewScope.dispCalMonth
-1 ,1).getDay();

Here I get the current year and month.
The number of days in the month is calculated by getting day zero of next
month. JavaScript sees the request for day zero of a month as being a request
for the last day of the previous month. It is a great shortcut because
you don’t need to worry about calculating leapyears, the javascript processor
does all that for you. In javascript January is defined as 0 but in @formula
language January is defined as 1. This explains why I don’t need to add
one to the month.

To get the first day in the month I
pass in the 1st of the current month ( hence the -1 on the month variable
) and call the getDay function. This returns a 0 for Sunday, 1 for Monday
and so on. If your doing a European style calendar where Monday is the
first day on the left make sure you adjust the value returned here as required.

The number that we got back for the
first day in the month is also the number of blank entries we need to pad
the calendar with. To do this in XPages we can use a very simple repeat
control. Repeat controls don’t need to be linked to Domino data sources.
In this case I’m setting the repeat’s source as an integer and the repeat
will repeat that many times. Inside the repeat control I just have a blank
span.

<xp:repeat
id="calBlanks" rows="7" value="#{javascript:viewScope.firstDayInMonth}"
var="calblankVar">
<xp:span styleClass="calBlank" />
</xp:repeat>

Being able to do a repeat based on an
integer also makes generating the actual calendar spans very easy also.
We already have the number of days in the month thanks to the zero day
trick explained above.



<xp:repeat id="repeat1"
rows="31" value="#{javascript:viewScope.daysInMonth}"
IndexVar="calIndex" var="calVar">
<xp:text escape="true" id="computedField1" value="#{javascript:calVar
+ 1}">
<xp:this.styleClass><!DATA[#{javascript:if (calIndex != 0){

       if (calIndex + firstDayInMonth  % 7 ==
0){
       return “firstday”;
} else {
       return “”;
} } }>


</xp:this.styleClass>
<xp:this.converter>
<xp:convertNumber type="number" integerOnly="true"
/>
</xp:this.converter>
</xp:text>
</xp:repeat>


Make sure the repeats max is set to
31 ( the default is 30 and you’ll wonder why certain months don’t show
that 31st day if you forget to change the default ). Inside my repeat I
have a computed field set to display the repeats index plus one ( the index
starts at zero ). I am also calculating the style class so that every eight
span ( including the blank spans ) has a special css class assigned to
it that ensures the row moves down to the next next row of the calendar.

We now have a very simple calendar in
XPages. With some extra coding you can add some forward and backwards links
above the calendar that will add or subtract one to the viewScope month/year
variable and then do a partial update of the panel containing the calendar.
Here’s what my final calendar looks like with the extra coding completed.

A picture named M3

As you can see I have also redone my
calendar CSS so that it blends in well with the oneUI scheme.

Tagged with: ,
Posted in None

Advanced XPages : Debugging Scoped Variables

Probably one of the most useful features
in XPages has to be the scope variables, with proper planning you can really
make good use of them and eliminate the need to store temporary values
in backend notes documents. As I showed in a recent blog entry
you can put anything into a scope variable, including a hashmap and you
can then run a repeat control off the hashmap. Well the scope variables
themselves are also hashmaps so why not use the same technique to see what’s
in them.

There are four scope variables that
you can use, applicationScope, sessionScope, requestScope and viewScope.
To make it easier to debug an application that is using scoped variables
I have created four new custom controls, one for each of the four scoped
variables. The code in the custom controls is simple.

<?xml version="1.0"
encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core"&gt;
<xp:panel id="applicationVars" styleClass="debugPanel">
<xp:table styleClass="debug">
<xp:tr>
<th>Variable Name</th>
<th>Variable Content</th>
</xp:tr>
<xp:repeat id="varRepeat" rows="30" value="#{javascript:applicationScope.keySet();}"
var="scopeData">
<xp:tr>
<xp:td>
<xp:text escape="true" id="varName" value="#{javascript:scopeData}"
/>
</xp:td>
<xp:td>
<xp:text escape="true" id="varValue" value="#{javascript:applicationScope.get(scopeData)}"
/>
</xp:td>
</xp:tr>
</xp:repeat>
</xp:table>
</xp:panel>
</xp:view>

For the other custom controls you just
need to replace applicationScope with the other scope variables.

Using your new custom controls is easy,
just add them to the bottom of any page where you need to keep an eye on
the scoped variables. If your only using the sessionScope on a page then
you just need to add that custom control, if your making use of the requestScope
then just include that custom control.

I also like to create a new xPage in
my applications called ‘debug’ where I put in the custom controls for the
application and session scopes for easy access to them.

Don’t forget to remove ( or hide ) the
debug info before releasing your application.

Tagged with: , ,
Posted in None

XPages for iPhone

Well kinda….

Developing a web application for the
iPhone or any mobile browser is a bit different from developing for a desktop
browser. You need to take into account the size of the screen, the amount
of css file external JavaScript files that are downloaded and, in the case
of the iPhone, you may even want to get your application to conform to
the Apple
iPhone Web User Interface guidelines
.

If your developing an XPages application
you could just leave it as is and quite a lot of your application will
work on the iPhone. It will look exactly like it does on the desktop web
browser but a lot smaller. The dojo stuff seems to work ok so far, even
partial refreshes seem to work but there is a lot more you could do for
your iPhone users.

Lets start by redirecting your iPhone
users to a different page that might be customized for the iPhone. This
is actually pretty simple. In the beforePageLoads event for the page you
want to redirect FROM you can put in the following serverside JavaScript
:

var uAgent = context.getUserAgent().getUserAgent();

if (uAgent.match("iPhone") != null){
       context.redirectToPage("/iPhone.xsp");
}

By looking at the userAgent string provided
by the users browser we can quickly redirect to a different page. Nice
and simple.

If your application is using a theme
document then you could also make sure that a special iPhone CSS file is
loaded, for example

<resource rendered="#{javascript:context.getUserAgent().getUserAgent().match("iPhone")}">
<content-type>text/css</content-type>
<href>iPhone.css</href>
</resource>

Adding a similar but reversed rendering
command to the rest of your css files in the theme document would make
sure that those css files are not loaded when using the iPhone.

Obviously the same concepts will work
for any browser, mobile or desktop. So who knows maybe soon we’ll start
seeing Xpage applications that contain multiple interfaces based on the
browser that is accessing them.  I know I’m going to work on an iPhone
interface for the XPages Phonebook, who knows maybe there will be another
short tutorial on how I build it.

Tagged with: ,
Posted in None
Archives