home *** CD-ROM | disk | FTP | other *** search
/ Chip 2000 May / Chip_2000-05_cd1.bin / zkuste / Perl / ActivePerl-5.6.0.613.msi / 䆊䌷䈹䈙䏵-䞅䞆䞀㡆䞃䄦䠥 / _112c5502bb99975c064c262126c5f64d < prev    next >
Text File  |  2000-03-15  |  9KB  |  549 lines

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