jonnyfolk has asked for the wisdom of the Perl Monks concerning the following question:

A while back I asked a question about converting Date::Calc to HTML::CalendarMonth. The help I received enabled me to achieve a set of calendars in list form, one on top of the other.

I have decided to revisit this to try to put it into a container table, to provide a neater layout. To do this I need to produce an array of new tables to place into the container. The information for this is at Mojotoad's Calendar Test page.

Unfortunately I haven't been able to produce an array which works.
Taking a string of dates converted from Date::Calc I have:
while (defined $dates[0]) { my $days = $dates[0]; my ($year, $month, $day) = Add_Delta_Days(1,1,1, $days - 1); my $new_c = "new HTML::CalendarMonth ( year => $year, month => $month) +,"; push (@cals, $new_c); @dates = CreateCal($year, $month, @dates); }
If I print @cals it seems to reproduce the example on the Test Calendar page, but on running the rest of the example I end up with a blank screen:
# Embolden headers foreach (@cals) { $_->item($_->month,$_->year)->wrap_content(font({size => '2'})); $_->item($_->dayheaders)->wrap_content(font({size => '1'})); $_->item(15,16,17)->wrap_content(font({size => 4, color => 'red'})); } # Generate container table my $t = new HTML::ElementTable ( maxrow => 1, maxcol => 4 ); # Populate container table foreach (0..$#cals) { $t->cell(0,$_)->push_content($cals[$_]); } print $t->as_HTML; exit; sub CreateCal { my ($cyear, $cmonth, @dates) = @_; my (@days, @temp); foreach my $days (@dates) { my ($year, $month, $day) = Add_Delta_Days(1,1,1, $days - 1); if ($year == $cyear && $month == $cmonth) { push (@days, $day); } else { push (@temp, $days); } } return @temp; }
could anyone tell me why my $new_c approach is failing to produce a viable array, and suggest how I should be going about this?

Replies are listed 'Best First'.
Re: Generating a container table in HTML::CalendarMonth
by Mr. Muskrat (Canon) on Mar 18, 2003 at 16:00 UTC

    my $new_c = "new HTML::CalendarMonth ( year => $year, month => $month),";

    You have created a new scalar $new_c containing the string "new HTML::CalendarMonth ( year => $year, month => $month),". Remove the quotes and the trailing comma and it looks like it should work.

      Mr. Muskrat, my guardian angel! If we survive the war I'll buy you a beer!! :)
Re: Generating a container table in HTML::CalendarMonth
by jonnyfolk (Vicar) on Mar 18, 2003 at 22:38 UTC
    Hrrmm...
    I've got myself stuck on how to get @days into each table. I've re-ordered my approach and would imagine that combining @dates with $new_c in a hash would be the way to go but I'm not sure how to do it.

    the framework I am considering is shown below - if anyone can give me some pointers I'd be very grateful.

    while (defined $dates[0]) { my $days = $dates[0]; my ($year, $month, $day) = Add_Delta_Days(1,1,1, $days - 1); @dates = CreateCal($year, $month, @dates); } exit(0); sub CreateCal { my ($cyear, $cmonth, @dates) = @_; my (@days, @temp); my $days; foreach my $days (@dates) { my ($year, $month, $day) = Add_Delta_Days(1,1,1, $days - 1); if ($year == $cyear && $month == $cmonth) { push (@days, $day); } else { push (@temp, $days); } } if (@temp) { my $new_c = new HTML::CalendarMonth(month => $cmonth, year => $c +year,); push (@cals, $new_c); return @temp; } else { # Embolden headers foreach (@cals) { $_->item($_->month,$_->year)->wrap_content(font({size => '2'})) +; $_->item($_->dayheaders)->wrap_content(font({size => '1'})); $_->item(@days)->wrap_content(font({size => 4, color => 'red'})); #print "this is getting through"; # Generate container table my $t = new HTML::ElementTable ( maxrow => 1, maxcol => 6 ); # Populate container table foreach (0..$#cals) { $t->cell(0,$_)->push_content($cals[$_]); } print $t->as_HTML; exit; } } }

      At first glance I see that here:

      while (defined $dates[0]) { my $days = $dates[0]; my ($year, $month, $day) = Add_Delta_Days(1,1,1, $days - 1); @dates = CreateCal($year, $month, @dates); }
      you are calling Add_Delta_Days. Then you call it again in the CreateCal subroutine with different data.

      Is it supposed to do that? Maybe I'm not understanding what you hope to acheive.

Re: Generating a container table in HTML::CalendarMonth
by Mr. Muskrat (Canon) on Mar 25, 2003 at 16:46 UTC

    Not exactly sure if this is what you are looking for... I basicly took my old code from Solution for Date::Calc to HTML::CalendarMonth and pasted in the new code that you wrote.

    #!/usr/bin/perl use strict; use warnings; use Date::Calc qw(:all); use CGI qw(:standard); use HTML::AsSubs; use HTML::Element; use HTML::CalendarMonth; # @dates has already been sorted my @dates = ( 730000, 731158, 731159, 731160, 731161, 731178, 735000 ) +; my @cals; print header(), start_html(-title => "Calendars"); while ( defined $dates[0] ) { my $days = $dates[0]; my ( $year, $month, $day ) = Add_Delta_Days( 1, 1, 1, $days - 1 ); my $new_c = new HTML::CalendarMonth ( year => $year, month => $month + ); push ( @cals, $new_c ); @dates = CreateCal( $year, $month, @dates ); } # Embolden headers foreach my $cal ( @cals ) { $cal->item( $cal->month, $cal->year )->wrap_content( font({ size => + '2' }) ); $cal->item( $cal->dayheaders )->wrap_content( font({ size => '1' }) + ); $cal->item( 15, 16, 17 )->wrap_content( font({ size => 4, color => +'red' }) ); } # Generate container table my $t = new HTML::ElementTable ( maxrow => 1, maxcol => 4 ); # Populate container table for my $calnum ( 0 .. $#cals ) { $t->cell( 0, $calnum )->push_content( $cals[$calnum] ); } print $t->as_HTML; print end_html(); exit(0); sub CreateCal { my ( $cyear, $cmonth, @dates ) = @_; my ( @days, @temp ); foreach my $days ( @dates ) { my ( $year, $month, $day ) = Add_Delta_Days( 1, 1, 1, $days - 1 ); if ( $year == $cyear && $month == $cmonth ) { push ( @days, $day ); } else { push ( @temp, $days ); } } return @temp; }

    added It does put the calendars into a container table.

      Hi Mr. Muskrat, thanks for getting back to me.

      I had more or less arrived at the script you propose, which does indeed push the calendars into the container table. The problem is that the line

      $cal->item( 15, 16, 17 )->wrap_content( font({ size => 4, color => 're +d' }) );
      dictates the days highlighted, rather than the array @days.

      My challenge is to associate each @days with its corresponding $new_c

      The code below I hope shows a bit more clearly what I'm trying to achieve - tho' it doesn't work - perhaps you wouldn't mind taking a look and giving me your comments. (I've done very little with hashes so far so I'm guessing a little bit on how this might be achieved).

      #!/usr/bin/perl -w use strict; use CGI qw(:standard); use Date::Calc qw(:all); use CGI::Carp qw(fatalsToBrowser warningsToBrowser); use lib '/home/users/t/my_site.com-90978/lib'; use HTML::AsSubs; use HTML::Element; use HTML::CalendarMonth; # @dates has already been sorted my @dates = ( 730000, 731158, 731159, 731160, 731161, 731178, 735000 ) +; my @cals; print header(), start_html(-title => "Calendars"); # As long as there is a date left in @dates while (defined $dates[0]) { # get the first value from @dates leaving @dates alone my $days = $dates[0]; # find out the year, month and day so we can create a calendar my ($year, $month, $day) = Add_Delta_Days(1,1,1, $days - 1); # run the CreateCal subroutine with the year and month from the firs +t date # store the returned value in @dates so it can be used the next time + through the while loop @dates = CreateCal($year, $month, @dates); } exit(0); sub CreateCal { # Get the year and month for the calendar # as well as the @dates to use my ($cyear, $cmonth, @dates) = @_; # set up some variables that are local to this subroutine my (@days, @temp); my %calendar; my $new_c; my $t; # Process each $days in @dates foreach my $days (@dates) { # Get the year, month and day of $days my ($year, $month, $day) = Add_Delta_Days(1,1,1, $days - 1); # does it match the calendar we are creating? if ($year == $cyear && $month == $cmonth) { # if yes, then add the $day to @days push (@days, $day); } else { # if no, then add the $days to @temp push (@temp, $days); } } #while there are spare $days remaining if (@temp) { my $new_c = new HTML::CalendarMonth(month => $cmonth, year => $c +year,); #Create hash linking $new_c and @days %calendar = ($new_c => @days); return @temp; #when all $days are used up: } else { # Embolden headers #throw new calendar with @days foreach ($new_c{@days}) { $_->item($_->month,$_->year)->wrap_content(font({size => '2'})) +; $_->item($_->dayheaders)->wrap_content(font({size => '1'})); $_->item(@days)->wrap_content(font({size => 4, color => 'red'})); # Generate container table my $t = new HTML::ElementTable ( maxrow => 1, maxcol => 6 ); # Populate container table foreach (0..$#cals) { $t->cell(0,$_)->push_content($cals[$_]); } print $t->as_HTML; } } } #There may be a lot of gobbledygook here but I hope it gives an idea o +f what I'm trying to do with this approach. #Other issue is re-sorting so the calendars are placed in the table in + order.

        I think I have solved your problem jonnyfolk.

        #!/usr/bin/perl use strict; use warnings; use CGI qw( :standard ); use HTML::CalendarMonth; use HTML::AsSubs; use HTML::Element; use Date::Calc qw( :all ); # @dates has already been sorted my @dates = ( 730000, 731158, 731159, 731160, 731161, 731178, 735000 ) +; my ( @cals, @days ); print start_html(-title => 'Calendars'); while ( defined $dates[0] ) { my $days = $dates[0]; my ( $year, $month, $day ) = Add_Delta_Days( 1, 1, 1, $days - 1 ); my $new_c = new HTML::CalendarMonth ( year => $year, month => $month + ); @dates = CreateCal( $year, $month, @dates ); push( @cals, $new_c ); } # Embolden headers foreach my $calnum ( 0 .. $#cals ) { my $cal = $cals[$calnum]; my @color = @{ $days[$calnum] }; # the days to be colored $cal->item( $cal->month, $cal->year )->wrap_content( font({ size => + '2' }) ); $cal->item( $cal->dayheaders )->wrap_content( font({ size => '1' }) + ); $cal->item( @color )->wrap_content( font({ size => 4, color => 'red +' }) ); } # Generate container table my $t = new HTML::ElementTable ( maxrow => 1, maxcol => 4 ); # Populate container table for my $calnum ( 0 .. $#cals ) { $t->cell( 0, $calnum )->push_content( $cals[$calnum] ); } print $t->as_HTML; print end_html(); exit(0); sub CreateCal { my ( $cyear, $cmonth, @dates ) = @_; my ( @day, @temp ); foreach my $days ( @dates ) { my ( $year, $month, $day ) = Add_Delta_Days( 1, 1, 1, $days - 1 ); if ( $year == $cyear && $month == $cmonth ) { push ( @day, $day ); } else { push ( @temp, $days ); } } push ( @days, [ @day ] ); # store the days of each calendar return @temp; }