home *** CD-ROM | disk | FTP | other *** search
/ Acorn User 10 / AU_CD10.iso / Updates / Perl / Perl_Libs / site_perl / HTML / Formatter.pm < prev    next >
Text File  |  1997-11-26  |  9KB  |  546 lines

  1. package HTML::Formatter;
  2.  
  3. # $Id: Formatter.pm,v 1.18 1997/11/26 15:39:14 aas Exp $
  4.  
  5. =head1 NAME
  6.  
  7. HTML::Formatter - Base class for HTML formatters
  8.  
  9. =head1 SYNOPSIS
  10.  
  11.  package HTML::FormatXX;
  12.  require HTML::Formatter;
  13.  @ISA=qw(HTML::Formatter);
  14.  
  15. =head1 DESCRIPTION
  16.  
  17. HTML formatters are able to format a HTML syntax tree into various
  18. printable formats.  Different formatters produce output for different
  19. output media.  Common for all formatters are that they will return the
  20. formatted output when the format() method is called.  Format() takes a
  21. HTML::Element as parameter.
  22.  
  23. =head1 SEE ALSO
  24.  
  25. L<HTML::FormatText>, L<HTML::FormatPS>, L<HTML::Element>
  26.  
  27. =head1 COPYRIGHT
  28.  
  29. Copyright (c) 1995-1997 Gisle Aas. All rights reserved.
  30.  
  31. This library is free software; you can redistribute it and/or
  32. modify it under the same terms as Perl itself.
  33.  
  34. =head1 AUTHOR
  35.  
  36. Gisle Aas <aas@oslonett.no>
  37.  
  38. =cut
  39.  
  40.  
  41. require HTML::Element;
  42.  
  43. use strict;
  44. use Carp;
  45. use UNIVERSAL qw(can);
  46.  
  47. sub new
  48. {
  49.     my($class,%arg) = @_;
  50.     my $self = bless { $class->default_values }, $class;
  51.     $self->configure(\%arg) if scalar(%arg);
  52.     $self;
  53. }
  54.  
  55. sub default_values
  56. {
  57.     ();
  58. }
  59.  
  60. sub configure
  61. {
  62.     my($self, $arg) = @_;
  63.     for (keys %$arg) {
  64.     warn "Unknown configure argument '$_'" if $^W;
  65.     }
  66.     $self;
  67. }
  68.  
  69. sub format
  70. {
  71.     my($self, $html) = @_;
  72.     $self->begin();
  73.     $html->traverse(
  74.     sub {
  75.         my($node, $start, $depth) = @_;
  76.         if (ref $node) {
  77.         my $tag = $node->tag;
  78.         my $func = $tag . '_' . ($start ? "start" : "end");
  79.         # Use UNIVERSAL::can so that we can recover if
  80.         # a handler is not defined for the tag.
  81.         if (can($self, $func)) {
  82.             return $self->$func($node);
  83.         } else {
  84.             return 1;
  85.         }
  86.         } else {
  87.         $self->textflow($node);
  88.         }
  89.         1;
  90.     }
  91.      );
  92.     $self->end();
  93.     join('', @{$self->{output}});
  94. }
  95.  
  96. sub begin
  97. {
  98.     my $self = shift;
  99.  
  100.     # Flags
  101.     $self->{anchor}    = 0;
  102.     $self->{underline} = 0;
  103.     $self->{bold}      = 0;
  104.     $self->{italic}    = 0;
  105.     $self->{center}    = 0;
  106.     $self->{nobr}      = 0;
  107.  
  108.     $self->{font_size}     = [3];   # last element is current size
  109.     $self->{basefont_size} = [3];
  110.  
  111.     $self->{markers} = [];          # last element is current marker
  112.     $self->{vspace} = undef;        # vertical space (dimension)
  113.  
  114.     $self->{output} = [];
  115. }
  116.  
  117. sub end
  118. {
  119. }
  120.  
  121. sub html_start { 1; }  sub html_end {}
  122. sub head_start { 0; }
  123. sub body_start { 1; }  sub body_end {}
  124.  
  125. sub header_start
  126. {
  127.     my($self, $level, $node) = @_;
  128.     my $align = $node->attr('align');
  129.     if (defined($align) && lc($align) eq 'center') {
  130.     $self->{center}++;
  131.     }
  132.     1,
  133. }
  134.  
  135. sub header_end
  136. {
  137.     my($self, $level, $node) = @_;
  138.     my $align = $node->attr('align');
  139.     if (defined($align) && lc($align) eq 'center') {
  140.     $self->{center}--;
  141.     }
  142. }
  143.  
  144. sub h1_start { shift->header_start(1, @_) }
  145. sub h2_start { shift->header_start(2, @_) }
  146. sub h3_start { shift->header_start(3, @_) }
  147. sub h4_start { shift->header_start(4, @_) }
  148. sub h5_start { shift->header_start(5, @_) }
  149. sub h6_start { shift->header_start(6, @_) }
  150.  
  151. sub h1_end   { shift->header_end(1, @_) }
  152. sub h2_end   { shift->header_end(2, @_) }
  153. sub h3_end   { shift->header_end(3, @_) }
  154. sub h4_end   { shift->header_end(4, @_) }
  155. sub h5_end   { shift->header_end(5, @_) }
  156. sub h6_end   { shift->header_end(6, @_) }
  157.  
  158. sub br_start
  159. {
  160.     my $self = shift;
  161.     $self->vspace(0, 1);
  162. }
  163.  
  164. sub hr_start
  165. {
  166.     my $self = shift;
  167.     $self->vspace(1);
  168. }
  169.  
  170. sub img_start
  171. {
  172.     shift->out(shift->attr('alt') || "[IMAGE]");
  173. }
  174.  
  175. sub a_start
  176. {
  177.     shift->{anchor}++;
  178.     1;
  179. }
  180.  
  181. sub a_end
  182. {
  183.     shift->{anchor}--;
  184. }
  185.  
  186. sub u_start
  187. {
  188.     shift->{underline}++;
  189.     1;
  190. }
  191.  
  192. sub u_end
  193. {
  194.     shift->{underline}--;
  195. }
  196.  
  197. sub b_start
  198. {
  199.     shift->{bold}++;
  200.     1;
  201. }
  202.  
  203. sub b_end
  204. {
  205.     shift->{bold}--;
  206. }
  207.  
  208. sub tt_start
  209. {
  210.     shift->{teletype}++;
  211.     1;
  212. }
  213.  
  214. sub tt_end
  215. {
  216.     shift->{teletype}--;
  217. }
  218.  
  219. sub i_start
  220. {
  221.     shift->{italic}++;
  222.     1;
  223. }
  224.  
  225. sub i_end
  226. {
  227.     shift->{italic}--;
  228. }
  229.  
  230. sub center_start
  231. {
  232.     shift->{center}++;
  233.     1;
  234. }
  235.  
  236. sub center_end
  237. {
  238.     shift->{center}--;
  239. }
  240.  
  241. sub nobr_start
  242. {
  243.     shift->{nobr}++;
  244.     1;
  245. }
  246.  
  247. sub nobr_end
  248. {
  249.     shift->{nobr}--;
  250. }
  251.  
  252. sub wbr_start
  253. {
  254.     1;
  255. }
  256.  
  257. sub font_start
  258. {
  259.     my($self, $elem) = @_;
  260.     my $size = $elem->attr('size');
  261.     return 1 unless defined $size;
  262.     if ($size =~ /^\s*[+\-]/) {
  263.     my $base = $self->{basefont_size}[-1];
  264.     $size = $base + $size;
  265.     }
  266.     push(@{$self->{font_size}}, $size);
  267.     1;
  268. }
  269.  
  270. sub font_end
  271. {
  272.     my($self, $elem) = @_;
  273.     my $size = $elem->attr('size');
  274.     return unless defined $size;
  275.     pop(@{$self->{font_size}});
  276. }
  277.  
  278. sub basefont_start
  279. {
  280.     my($self, $elem) = @_;
  281.     my $size = $elem->attr('size');
  282.     return unless defined $size;
  283.     push(@{$self->{basefont_size}}, $size);
  284.     1;
  285. }
  286.  
  287. sub basefont_end
  288. {
  289.     my($self, $elem) = @_;
  290.     my $size = $elem->attr('size');
  291.     return unless defined $size;
  292.     pop(@{$self->{basefont_size}});
  293. }
  294.  
  295. # Aliases for logical markup
  296. BEGIN {
  297.     *cite_start   = \&i_start;
  298.     *cite_end     = \&i_end;
  299.     *code_start   = \&tt_start;
  300.     *code_end     = \&tt_end;
  301.     *em_start     = \&i_start;
  302.     *em_end       = \&i_end;
  303.     *kbd_start    = \&tt_start;
  304.     *kbd_end      = \&tt_end;
  305.     *samp_start   = \&tt_start;
  306.     *samp_end     = \&tt_end;
  307.     *strong_start = \&b_start;
  308.     *strong_end   = \&b_end;
  309.     *var_start    = \&tt_start;
  310.     *var_end      = \&tt_end;
  311. }
  312.  
  313. sub p_start
  314. {
  315.     my $self = shift;
  316.     $self->vspace(1);
  317.     1;
  318. }
  319.  
  320. sub p_end
  321. {
  322.     shift->vspace(1);
  323. }
  324.  
  325. sub pre_start
  326. {
  327.     my $self = shift;
  328.     $self->{pre}++;
  329.     $self->vspace(1);
  330.     1;
  331. }
  332.  
  333. sub pre_end
  334. {
  335.     my $self = shift;
  336.     $self->{pre}--;
  337.     $self->vspace(1);
  338. }
  339.  
  340. BEGIN {
  341.     *listing_start = \&pre_start;
  342.     *listing_end   = \&pre_end;
  343.     *xmp_start     = \&pre_start;
  344.     *xmp_end       = \&pre_end;
  345. }
  346.  
  347. sub blockquote_start
  348. {
  349.     my $self = shift;
  350.     $self->vspace(1);
  351.     $self->adjust_lm( +2 );
  352.     $self->adjust_rm( -2 );
  353.     1;
  354. }
  355.  
  356. sub blockquote_end
  357. {
  358.     my $self = shift;
  359.     $self->vspace(1);
  360.     $self->adjust_lm( -2 );
  361.     $self->adjust_rm( +2 );
  362. }
  363.  
  364. sub address_start
  365. {
  366.     my $self = shift;
  367.     $self->vspace(1);
  368.     $self->i_start(@_);
  369.     1;
  370. }
  371.  
  372. sub address_end
  373. {
  374.     my $self = shift;
  375.     $self->i_end(@_);
  376.     $self->vspace(1);
  377. }
  378.  
  379. # Handling of list elements
  380.  
  381. sub ul_start
  382. {
  383.     my $self = shift;
  384.     $self->vspace(1);
  385.     push(@{$self->{markers}}, "*");
  386.     $self->adjust_lm( +2 );
  387.     1;
  388. }
  389.  
  390. sub ul_end
  391. {
  392.     my $self = shift;
  393.     pop(@{$self->{markers}});
  394.     $self->adjust_lm( -2 );
  395.     $self->vspace(1);
  396. }
  397.  
  398. sub li_start
  399. {
  400.     my $self = shift;
  401.     $self->bullet($self->{markers}[-1]);
  402.     $self->adjust_lm(+2);
  403.     1;
  404. }
  405.  
  406. sub bullet
  407. {
  408.     shift->out(@_);
  409. }
  410.  
  411. sub li_end
  412. {
  413.     my $self = shift;
  414.     $self->vspace(1);
  415.     $self->adjust_lm( -2);
  416.     my $markers = $self->{markers};
  417.     if ($markers->[-1] =~ /^\d+/) {
  418.     # increment ordered markers
  419.     $markers->[-1]++;
  420.     }
  421. }
  422.  
  423. BEGIN {
  424.     *menu_start = \&ul_start;
  425.     *menu_end   = \&ul_end;
  426.     *dir_start  = \&ul_start;
  427.     *dir_end    = \&ul_end;
  428. }
  429.  
  430. sub ol_start
  431. {
  432.     my $self = shift;
  433.  
  434.     $self->vspace(1);
  435.     push(@{$self->{markers}}, 1);
  436.     $self->adjust_lm(+2);
  437.     1;
  438. }
  439.  
  440. sub ol_end
  441. {
  442.     my $self = shift;
  443.     $self->adjust_lm(-2);
  444.     pop(@{$self->{markers}});
  445.     $self->vspace(1);
  446. }
  447.  
  448.  
  449. sub dl_start
  450. {
  451.     my $self = shift;
  452.     $self->adjust_lm(+2);
  453.     $self->vspace(1);
  454.     1;
  455. }
  456.  
  457. sub dl_end
  458. {
  459.     my $self = shift;
  460.     $self->adjust_lm(-2);
  461.     $self->vspace(1);
  462. }
  463.  
  464. sub dt_start
  465. {
  466.     my $self = shift;
  467.     $self->vspace(1);
  468.     1;
  469. }
  470.  
  471. sub dt_end
  472. {
  473. }
  474.  
  475. sub dd_start
  476. {
  477.     my $self = shift;
  478.     $self->adjust_lm(+6);
  479.     $self->vspace(0);
  480.     1;
  481. }
  482.  
  483. sub dd_end
  484. {
  485.     shift->adjust_lm(-6);
  486. }
  487.  
  488.  
  489. # Things not formated at all
  490. sub table_start { shift->out('[TABLE NOT SHOWN]'); 0; }
  491. sub form_start  { shift->out('[FORM NOT SHOWN]');  0; }
  492.  
  493.  
  494.  
  495. sub textflow
  496. {
  497.     my $self = shift;
  498.     if ($self->{pre}) {
  499.     # strip leading and trailing newlines so that the <pre> tags 
  500.     # may be placed on lines of their own without causing extra
  501.     # vertical space as part of the preformatted text
  502.     $_[0] =~ s/\n$//;
  503.     $_[0] =~ s/^\n//;
  504.     $self->pre_out($_[0]);
  505.     } else {
  506.     for (split(/(\s+)/, $_[0])) {
  507.         next unless length $_;
  508.         $self->out($_);
  509.     }
  510.     }
  511. }
  512.  
  513.  
  514.  
  515. sub vspace
  516. {
  517.     my($self, $min, $add) = @_;
  518.     my $old = $self->{vspace};
  519.     if (defined $old) {
  520.     my $new = $old;
  521.     $new += $add || 0;
  522.     $new = $min if $new < $min;
  523.     $self->{vspace} = $new;
  524.     } else {
  525.     $self->{vspace} = $min;
  526.     }
  527.     $old;
  528. }
  529.  
  530. sub collect
  531. {
  532.     push(@{shift->{output}}, @_);
  533. }
  534.  
  535. sub out
  536. {
  537.     confess "Must be overridden my subclass";
  538. }
  539.  
  540. sub pre_out
  541. {
  542.     confess "Must be overridden my subclass";
  543. }
  544.  
  545. 1;
  546.