Category: HTML
Author/Contact Info tame1 jon@central-design.com
Description: A popup calendar to fill out date fields in forms. The only javascript used is in the links around the dates, as in "opener.document.forms[0].$field.value=$newval; self.close()" so it's safe across just about any browser version. Unlike all those javascript-only popup calendars.
package FES::Util::Calendar;
#PerlHandler
####################################################################
#===================================================================
# $Id: Calendar.pm,v 1.4 2002/05/31 13:54:19 jrobison Exp $
#-------------------------------------------------------------------
# Tag:      $Name:  $
# Revision: $Revision: 1.4 $
# Date:     $Date: 2002/05/31 13:54:19 $
# Author:   $Author: jrobison $
# Description: Calendar.pm is a wrapper around the calendar
#              which accepts input in order to determine what
#              data to present in the calendar.
# Inputs: act=calendar
#         field=name of field in main form to populate
#         string=year,$year,month,$month,begin,$earliest,end,$latest
# Call:
# <a href="javascript: void(0);
#           window.open('your_controller?act=calendar&field=date&strin
+g=','cal',
#          'width=220,height=270,screenX=200,screenY=300,titlebar=no,t
+itle=no');"
# Required Edits:
#          You will need to edit the $cal->header javascript to point
#          to the correct controller for your application. i.e. everyw
+here
#          I have /fes? you will need to put in your url. For mod_perl
+, obviously
#          this will be your dispatching module. For CGI, just the url
+ of this
#          script (After you've fixed the input parsing to use CGI, no
+t
#          Apache::Request.
#
# CGI use:
#          This module is obviously made to use mod_perl, probably in 
+an
#          MCV environment. Conversion to regular CGI should be relati
+vely
#          simple and is left as an exercise for the reader. <-- heheh
+eheh
# Dates:
#          I work dates in a YYYYMMDD format, no - or /
#          This makes date comparison easier, etc.
#          If you need another format, I suggest you edit sub padZero.
+ That
#          would be the easiest place to add -'s or /'s.
#          If you want to totally re-arrange the date, you'll have to 
+do more.
#####################################################################
use strict;
use Apache::Request;
use Apache::Constants         qw/ :common /;
use Date::Calc                qw/ Days_in_Month /;
use HTML::CalendarMonthSimple;

sub handler {
  my $r = Apache::Request->new(shift);
  ## BEGIN parse input arguments
    my $input = {};
    my @params = $r->param;
    foreach (@params) {
        $input->{$_} = $r->param($_);
    }

    ## Currently, $input->{'string'} holds an comma delimited string, 
+if anything.
    ## it needs to be a hash built from that array.
    ## BEGIN AWFUL HACK ##############################################
+####
    my @stringy = split(/\,/,$input->{'string'}); # This is an awful h
+ack.
    delete $input->{'string'};                    # Just something to 
+work,
                                                  # since my in-house 
+mod_perl
    for (my $i = 0;$i < scalar(@stringy);$i++) {  # parses input diffe
+rently
  my $v = $i + 1;
  $input->{'string'}{$stringy[$i]} = $stringy[$v];
  $i++;
    }
    ## Now, $input->{'string'} will hold {month}=6, {year}=2003, etc.
    ## END AWFUL HACK ################################################
+####

  unless($input) {
    _error($r,"Maiking input failed");
    return DONE;
  }
    ## END parse input arguments

  ## Most of this is needed to keep the calendar small.
  ## CalendarMonthSimple does have other ways to pass in CSS class dat
+a,
  ## but for now this works.
  my $head = <<EOH;
  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
 <head> 
 <style type="text/css">
<!-- //hide from older browsers
body {
    font-family: Arial,Helvetica,Sans-serif;
    font-size: 8px;
    color: #0000ff;
    text-decoration: none;
}
td {
    font-family : Arial,Helvetica,Sans-serif;
    font-size : 9px;
    color : #000000;
    max-height: 10px;
}
*.head {
    font-family: Arial,Helvetica,Sans-serif;
    font-size: 12px;
    text-decoration: none;
    color: #000000;
    background-color: #d3d3d3;
}
td.head {
    font-family: Arial,Helvetica,Sans-serif;
    font-size: 12px;
    text-decoration: none;
    color: #000000;
    background-color: #9cc2cd;
}
th {
    font-family: Arial,Helvetica,Sans-serif;
    font-size: 10px;
    text-decoration: none;
    color: #000000;
    background-color: #d3d3d3;
}
A:link {
    font-family : Arial,Helvetica,Sans-serif;
    font-size : 8px;
    color : #0000ff;
    text-decoration : none;
}
        -->
 </style>
 <title>Calendar Window</title>
 </head> 
EOH

  $head .= "<body background=\"/images/backgrounds/blend4.gif\" onBlur
+=\"javascript: focus();\">";
  my $footer .= "</body>\n</html>";
  my $year   = $input->{'string'}{'year'} || ((localtime(time))[5] + 1
+900);
  my $current_month = (localtime(time))[4];
  my $display_month;
  my $month;
  if ($input->{'string'}{'month'}) {
        $month = $input->{'string'}{'month'} - 1;
    } else {
        $month = $current_month;
    }
    my $days_in_month = Days_in_Month($year,$month+1);

# Create the calendar object
    my $cal = new HTML::CalendarMonthSimple (
        month => $month+1,
        year  => $year,
                                                                      
+  );
    
# Set up some calendar view parameters
    $cal->border(0);
    $cal->cellalignment('center');
    $cal->vcellalignment('bottom');
    $cal->sharpborders('1');
    $cal->bgcolor('#badee6');
    $cal->todaycolor('yellow');
    $cal->weekendcolor('#ffbbbb');
    $cal->cellheight('10');
    
# ugly broken out like this, but easier to follow.
    my $last_month = $month;
    my $this_month = $month + 1;
    my $next_month = $month + 2;
    my $last_year  = $year - 1;
    my $next_year  = $year + 1;
    my $earliest = defined $input->{'string'}{'begin'} ? $input->{'str
+ing'}{'begin'} : '00000000';
    my $latest   = defined $input->{'string'}{'end'}   ? $input->{'str
+ing'}{'end'}   : '21000101';
    
    ## BEGIN set the header
    my ($y,$m) = ( $cal->year, $cal->monthname() );
    $cal->header("<table border=0 width=\"100%\">"
                             . "<tr>\n"
                             . "<td align=\"center\" class=\"head\"><a
+ href=\"javascript: document.location='/fes?act=calendar"
                             . "&field=$input->{field}&string=year,$ye
+ar,month,$last_month,begin,$earliest,end,$latest';\">\n"
                             . "<img src=\"/images/down.gif\" border=0
+></a>"
                             . " $m "
                             . " <a href=\"javascript: document.locati
+on='/fes?act=calendar"
                             . "&field=$input->{field}&string=year,$ye
+ar,month,$next_month,begin,$earliest,end,$latest';\">\n"
                             . "<img src=\"/images/up.gif\" border=0><
+/a>"
                             . "</td>\n"
                             . "<td align=\"center\" class=\"head\"><a
+ href=\"javascript: document.location='/fes?act=calendar"
                             . "&field=$input->{field}&string=year,$la
+st_year,month,$this_month,begin,$earliest,end,$latest';\">\n"
                             . "<img src=\"/images/down.gif\" border=0
+></a>"
                             . " $y "
                             . " <a href=\"javascript: document.locati
+on='/fes?act=calendar"
                             . "&field=$input->{field}&string=year,$ne
+xt_year,month,$this_month,begin,$earliest,end,$latest';\">\n"
                             . "<img src=\"/images/up.gif\" border=0><
+/a>"
                             . "</td>\n"
                             . "</tr></table>\n"
                             );
    ## END set the header

    unless ($cal) {
        _error($r,"Failed to make a calendar object!: $!");
        return DONE;
    }
    
    my $field    = $input->{'field'};
    for (my $i=1;$i<=$days_in_month;$i++) {
        my $date = $year . padZero($month+1) . padZero($i);
        if (($date >= $earliest) && ($date <= $latest)) {
            $cal->setdatehref($i,"\"javascript: opener.document.forms[
+0].$field.value='$date'; self.close();\"");
        }
    }
        
  print $r->send_http_header('text/html');
  print $head;
  print $cal->as_HTML;
  print $footer;
  
  return DONE;
}

sub padZero {
    my $in = shift;
    if ($in < 10) {
        $in = "0" . $in;
    }
    return $in;
}

sub _error {
    my $r = shift;
    my $error = shift;
    print $r->sent_http_header('text/html');
    print "<html><head><title>Error!</title></head>"
         . "<body bgcolor=\"white\"><h2 align='center'>$error</h2>\n";
    print "</body></html>\n";
}

1;
Replies are listed 'Best First'.
Re: Calendar.pm
by tame1 (Pilgrim) on Jun 03, 2002 at 14:36 UTC
    Also, I highly suggest that you edit CalendarMonthSimple.pm and change the full text days (Sunday, Monday, etc.) to two letter days, AND also remove the <P> and </P> tags from around the links. This will allow the calendar to be sized to show up in a window of around 220 by 220 - perfect for a popup like this.

    What does this little button do . .<Click>; "USER HAS SIGNED OFF FOR THE DAY"