-<% $data %>
<%init>
my %args = @_;
-my $type = $args{'type'};
my $header = $args{'header'};
my $rows = $args{'rows'};
my %opt = %{ $args{'opt'} };
#http://support.microsoft.com/kb/812935
#http://support.microsoft.com/kb/323308
-$HTML::Mason::Commands::r->headers_out->{'Cache-control'} = 'max-age=0';
+http_header('Cache-control' => 'max-age=0');
my $data = '';
my $XLS = new IO::Scalar \$data;
my $workbook = $format->{class}->new($XLS)
or die "Error opening Excel file: $!";
-my $worksheet = $workbook->add_worksheet(substr($opt{'title'},0,31));
+my $title = $opt{'title'};
+$title =~ s/[\[\]\:\*\?\/\/]//g;
+$title = substr($title, 0, 31);
+
+# append a single worksheet
+$m->comp( 'SELF:worksheet',
+ workbook => $workbook,
+ title => $title,
+ opt => \%opt,
+ header => $header,
+ rows => $rows
+);
+
+$workbook->close();# or die "Error creating .xls file: $!";
+
+http_header('Content-Length' => length($data) );
+$m->clear_buffer();
+$m->print($data);
+
+</%init>
+<%method worksheet>
+<%args>
+$workbook
+$title
+%opt
+$header
+$rows
+</%args>
+<%perl>
-$worksheet->protect();
+my $worksheet = $workbook->add_worksheet($title);
+
+#$worksheet->protect();
+
+my $style = $opt{style};
my($r,$c) = (0,0);
bg_color => 55, #22,
bottom => 3,
);
+my $footer_format = $workbook->add_format(
+ italic => 1,
+ locked => 1,
+ bg_color => 55,
+ top => 3,
+);
my $default_format = $workbook->add_format(locked => 0);
my %money_format;
my %date_format;
xl_parse_date_init();
-my $writer = sub {
+my %bold_format;
+
+my @widths;
+
+my $writer;
+$writer = sub {
# Wrapper for $worksheet->write.
# Do any massaging of the value/format here.
my ($r, $c, $value, $format) = @_;
+ #warn "writer called with format $format\n";
+
+ if ( ref $value eq 'ARRAY' ) {
+ # imitate the write_row() method: write the array into a column starting
+ # with $r.
+ # (currently only used in the footer; to use it anywhere else we'd need
+ # some way to return the number of rows written)
+ foreach my $v (@$value) {
+ $writer->($r, $c, $v, $format);
+ $r++;
+ }
+ return;
+ }
+
+ my $bold = 0;
+ my $date = 0;
+ if ( $style->[$c] eq 'b' or $value =~ /<b>/i ) { # the only one in common use
+ $value =~ s[</?b>][]ig;
+ if ( !exists($bold_format{$format}) ) {
+ $bold_format{$format} = $workbook->add_format();
+ $bold_format{$format}->copy($format);
+ $bold_format{$format}->set_bold();
+ }
+ $format = $bold_format{$format};
+ $bold = 1;
+ }
+
# convert HTML entities
# both Spreadsheet::WriteExcel and Excel::Writer::XLSX accept UTF-8 strings
$value = decode_entities($value);
$date_format{$format}->set_num_format('mmm dd yyyy');
}
$format = $date_format{$format};
+ $date = 1;
}
else {
# String: replace line breaks with newlines
$value =~ s/<BR>/\n/gi;
}
+ #warn "writing with format $format\n";
$worksheet->write($r, $c, $value, $format);
+
+ # estimate width
+ # use Font::TTFMetrics; # would work, but we can't redistribute the font...
+ my $width = length($value);
+ $width = 11 if $date;
+ $width *= 1.1 if $bold;
+ $width += 1; # pad it a little
+ $widths[$c] = $width if $width > ($widths[$c] || 0);
};
$writer->( $r, $c++, $_, $header_format ) foreach @$header;
if ( ref($item) eq 'CODE' ) {
$item = &{$item}();
}
- $writer->( $r, $c++, $item, $header_format );
+ $writer->( $r, $c++, $item, $footer_format );
}
}
-$workbook->close();# or die "Error creating .xls file: $!";
-
-http_header('Content-Length' => length($data) );
+for ( my $x = 0; $x < scalar @widths; $x++ ) {
+ $worksheet->set_column($x, $x, $widths[$x]);
+}
-</%init>
+</%perl>
+</%method>