Building WML Gadgets: A Calendar
Next and Previous Month Navigation
Adding next and previous month navigation is fairly straightforward. We simply determine what the next/previous month and year would be and use an appropriate <GO> tag with encoded name/value pairs.
Note: We determine the month and year up front to eliminate the need to do any processing later on (moving from Dec to Jan, or from Jan back to Dec).
The function Add_Delta_Days from the Date::Calc module allows us to do date math, adding days to a known date. Adding 31 to the first day of any month will give us a date in the following month, while subtracting 1 from the first day of any month will give us a date in the prior month. Such code resembles the following:
# Set next month/year ($nextyear,$nextmonth,$nextday) = Add_Delta_Days($year,$month,1,31); # Set prev month/year ($prevyear,$prevmonth,$prevday) = Add_Delta_Days($year,$month,1,-1);
We then use the variables when outputting the <GO> tags, similar to this:
<do type="accept" label="Back" name="Prev"> <go href="cal.pl?month=$prevmonth&year=$prevyear" /> </do>
The Finished Script
When we put it all together, the script is as follows:
Listing of cal.pl
#!/usr/bin/perl -w # Define modules use CGI qw(:standard); use Date::Calc ':all'; # Parse command line or name/value pairs # Command line: if (@ARGV) { $month = (shift @ARGV); $year = (shift @ARGV); } else { # Name/value pairs if ($ENV{REQUEST_METHOD} eq 'GET') { foreach $input (split("&",$ENV{QUERY_STRING})) { if ($input =~ /(.*)=(.*)/) { ($key,$value) = ($1, $2); # Add keyword/value pair to a list $inputs{$key} = $value; $month = $inputs{month}; $year = $inputs{year}; } } } } # If we don't have a valid date from params, # set date to today (server clock) if (!check_date($year,$month,1)) { ($year,$month,$day) = Today([$gmt]); } # Find weekday (Sun - Sat) of first of the month $firstdow = Day_of_Week($year,$month,"1"); # Convert Sun (7) to 0 if ("$firstdow" == "7") { $firstdow = 0; } # Month text $monthtext = Month_to_Text($month); # Set next month/year ($nextyear,$nextmonth,$nextday) = Add_Delta_Days($year,$month,1,31); # Set prev month/year ($prevyear,$prevmonth,$prevday) = Add_Delta_Days($year,$month,1,-1); # Pass WML header print header(-type=>'text/vnd.wap.wml'); # Print WML header and beginning tags print <<ENDHEADER; <?xml version="1.0"?> <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml"> <wml> <card> <do type="accept" label="Back" name="Prev"> <go href="cal.pl?month=$prevmonth&year=$prevyear" /> </do> <do type="option" label="Fwd" name="Next"> <go href="cal.pl?month=$nextmonth&year=$nextyear" /> </do> <p> $monthtext $year<br/> <table columns="7"> <tr><td> S </td><td> M </td><td> T </td><td> W </td> <td> T </td><td> F </td><td> S </td></tr> ENDHEADER # Start first date row print "<tr>"; # Print blank cells up to first day $x = 0; while ($x < $firstdow) { print "<td> </td>"; $x++; } # Start with first day $day = 1; # Work through month from first day through last while ($day <= Days_in_Month($year,$month)) { print "<td>"; if ($day < 10) { print " "; } print $day."|</td>"; $x++; # At end of week, close row if ($x == 7) { print "</tr>\n"; # If we aren't done, start new row if ($day != Days_in_Month($year,$month)) { print "<tr>"; } $x = 0 } $day++; } # Fill out last row (if applicable) # with blank cells if ($x ne 0) { while ($x <= 6) { print "<td> </td>"; $x++; } print "</tr>"; } # Close tags, card, and WML print <<ENDFOOTER; </table> </p> </card> </wml> ENDFOOTER
If a mobile browser without parameters calls the script, it will display the current month along with two buttons to move forward and backward by month, respectively. Alternatively, the script can be accessed with encoded name/value pairs to specify which month to display. For example, the following URL results in the display shown in the figure:
http:///cal.pl?month=4&year=2001
FIGURE 11.5
Room for Improvement
As with previous projects, several things could be added to improve our calendar:
- Better labels for our navigation keys-the first three letters of the month (e.g., "Dec"), for example, instead of "Back" and "Fwd"
- Marking the current date, perhaps with underlining.
- A navigation control to allow the user to specify a particular month to display
- A navigation control to display the current month
What Do You Want from WML?
I'm interested in hearing what you need/want to do with WML. I'll use some of the more challenging or common ideas in upcoming articles. Send your ideas to the address below.
About the Author
Steve Schafer is the chief operating officer of Progeny Linux Systems, a Linux-based consulting company in Indianapolis, Indiana. He has written several technical books and articles and can be reached at sschafer@synergy-tech.com.
# # #Page 5 of 5
This article was originally published on December 21, 2002