HTML.pm
Go to the documentation of this file.
1 #============================================================= -*-Perl-*-
2 #
3 # Pod::POM::View::HTML
4 #
5 # DESCRIPTION
6 # HTML view of a Pod Object Model.
7 #
8 # AUTHOR
9 # Andy Wardley <abw@kfs.org>
10 #
11 # COPYRIGHT
12 # Copyright (C) 2000 Andy Wardley. All Rights Reserved.
13 #
14 # This module is free software; you can redistribute it and/or
15 # modify it under the same terms as Perl itself.
16 #
17 # REVISION
18 # $Id: HTML.pm 84 2009-08-20 21:07:00Z ford $
19 #
20 #========================================================================
21 
22 package BASIS::Pod::POM::View::HTML;
23 
24 require 5.004;
25 
26 use strict;
27 use BASIS::Pod::POM::View;
28 use parent qw( BASIS::Pod::POM::View );
29 use vars qw( $VERSION $DEBUG $ERROR $AUTOLOAD );
30 use Text::Wrap;
31 
32 $VERSION = sprintf("%d.%02d", q$Revision: 1.6 $ =~ /(\d+)\.(\d+)/);
33 $DEBUG = 0 unless defined $DEBUG;
34 my $HTML_PROTECT = 0;
35 my @OVER;
36 
37 sub new {
38  my $class = shift;
39  my $self = $class->SUPER::new(@_)
40  || return;
41 
42  # initalise stack for maintaining info for nested lists
43  $self->{ OVER } = [];
44 
45  return $self;
46 }
47 
48 
49 sub view {
50  my ($self, $type, $item) = @_;
51 
52  if ($type =~ s/^seq_//) {
53  return $item;
54  }
55  elsif (UNIVERSAL::isa($item, 'HASH')) {
56  if (defined $item->{ content }) {
57  return $item->{ content }->present($self);
58  }
59  elsif (defined $item->{ text }) {
60  my $text = $item->{ text };
61  return ref $text ? $text->present($self) : $text;
62  }
63  else {
64  return '';
65  }
66  }
67  elsif (! ref $item) {
68  return $item;
69  }
70  else {
71  return '';
72  }
73 }
74 
75 
76 sub view_pod {
77  my ($self, $pod) = @_;
78  return "<html>\n<body bgcolor=\"#ffffff\">\n"
79  . $pod->content->present($self)
80  . "</body>\n</html>\n";
81 }
82 
83 
84 sub view_head1 {
85  my ($self, $head1) = @_;
86  my $title = $head1->title->present($self);
87  return "<h1>$title</h1>\n\n"
88  . $head1->content->present($self);
89 }
90 
91 
92 sub view_head2 {
93  my ($self, $head2) = @_;
94  my $title = $head2->title->present($self);
95  return "<h2>$title</h2>\n"
96  . $head2->content->present($self);
97 }
98 
99 
100 sub view_head3 {
101  my ($self, $head3) = @_;
102  my $title = $head3->title->present($self);
103  return "<h3>$title</h3>\n"
104  . $head3->content->present($self);
105 }
106 
107 
108 sub view_head4 {
109  my ($self, $head4) = @_;
110  my $title = $head4->title->present($self);
111  return "<h4>$title</h4>\n"
112  . $head4->content->present($self);
113 }
114 
115 
116 sub view_over {
117  my ($self, $over) = @_;
118  my ($start, $end, $strip);
119  my $items = $over->item();
120 
121  if (@$items) {
122 
123  my $first_title = $items->[0]->title();
124 
125  if ($first_title =~ /^\s*\*\s*/) {
126  # '=item *' => <ul>
127  $start = "<ul>\n";
128  $end = "</ul>\n";
129  $strip = qr/^\s*\*\s*/;
130  }
131  elsif ($first_title =~ /^\s*\d+\.?\s*/) {
132  # '=item 1.' or '=item 1 ' => <ol>
133  $start = "<ol>\n";
134  $end = "</ol>\n";
135  $strip = qr/^\s*\d+\.?\s*/;
136  }
137  else {
138  $start = "<ul>\n";
139  $end = "</ul>\n";
140  $strip = '';
141  }
142 
143  my $overstack = ref $self ? $self->{ OVER } : \@OVER;
144  push(@$overstack, $strip);
145  my $content = $over->content->present($self);
146  pop(@$overstack);
147 
148  return $start
149  . $content
150  . $end;
151  }
152  else {
153  return "<blockquote>\n"
154  . $over->content->present($self)
155  . "</blockquote>\n";
156  }
157 }
158 
159 
160 sub view_item {
161  my ($self, $item) = @_;
162 
163  my $over = ref $self ? $self->{ OVER } : \@OVER;
164  my $title = $item->title();
165  my $strip = $over->[-1];
166 
167  if (defined $title) {
168  $title = $title->present($self) if ref $title;
169  $title =~ s/$strip// if $strip;
170  if (length $title) {
171  my $anchor = $title;
172  $anchor =~ s/^\s*|\s*$//g; # strip leading and closing spaces
173  $anchor =~ s/\W/_/g;
174  $title = qq{<a name="item_$anchor"></a><b>$title</b>};
175  }
176  }
177 
178  return '<li>'
179  . "$title\n"
180  . $item->content->present($self)
181  . "</li>\n";
182 }
183 
184 
185 sub view_for {
186  my ($self, $for) = @_;
187  return '' unless $for->format() =~ /\bhtml\b/;
188  return $for->text()
189  . "\n\n";
190 }
191 
192 
193 sub view_begin {
194  my ($self, $begin) = @_;
195  return '' unless $begin->format() =~ /\bhtml\b/;
196  $HTML_PROTECT++;
197  my $output = $begin->content->present($self);
198  $HTML_PROTECT--;
199  return $output;
200 }
201 
202 
203 sub view_textblock {
204  my ($self, $text) = @_;
205  return $HTML_PROTECT ? "$text\n" : "<p>$text</p>\n";
206 }
207 
208 
209 sub view_verbatim {
210  my ($self, $text) = @_;
211  for ($text) {
212  s/&/&amp;/g;
213  s/</&lt;/g;
214  s/>/&gt;/g;
215  }
216  return "<pre>$text</pre>\n\n";
217 }
218 
219 
220 sub view_seq_bold {
221  my ($self, $text) = @_;
222  return "<b>$text</b>";
223 }
224 
225 
226 sub view_seq_italic {
227  my ($self, $text) = @_;
228  return "<i>$text</i>";
229 }
230 
231 
232 sub view_seq_code {
233  my ($self, $text) = @_;
234  return "<code>$text</code>";
235 }
236 
237 sub view_seq_file {
238  my ($self, $text) = @_;
239  return "<i>$text</i>";
240 }
241 
242 sub view_seq_space {
243  my ($self, $text) = @_;
244  $text =~ s/\s/&nbsp;/g;
245  return $text;
246 }
247 
248 
249 sub view_seq_entity {
250  my ($self, $entity) = @_;
251  return "&$entity;"
252 }
253 
254 
255 sub view_seq_index {
256  return '';
257 }
258 
259 
260 sub view_seq_link {
261  my ($self, $link) = @_;
262 
263  # view_seq_text has already taken care of L<http://example.com/>
264  if ($link =~ /^<a href=/ ) {
265  return $link;
266  }
267 
268  # full-blown URL's are emitted as-is
269  if ($link =~ m{^\w+://}s ) {
270  return make_href($link);
271  }
272 
273  $link =~ s/\n/ /g; # undo line-wrapped tags
274 
275  my $orig_link = $link;
276  my $linktext;
277  # strip the sub-title and the following '|' char
278  if ( $link =~ s/^ ([^|]+) \| //x ) {
279  $linktext = $1;
280  }
281 
282  # make sure sections start with a /
283  $link =~ s|^"|/"|;
284 
285  my $page;
286  my $section;
287  if ($link =~ m|^ (.*?) / "? (.*?) "? $|x) { # [name]/"section"
288  ($page, $section) = ($1, $2);
289  }
290  elsif ($link =~ /\s/) { # this must be a section with missing quotes
291  ($page, $section) = ('', $link);
292  }
293  else {
294  ($page, $section) = ($link, '');
295  }
296 
297  # warning; show some text.
298  $linktext = $orig_link unless defined $linktext;
299 
300  my $url = '';
301  if (defined $page && length $page) {
302  $url = $self->view_seq_link_transform_path($page);
303  }
304 
305  # append the #section if exists
306  $url .= "#$section" if defined $url and
307  defined $section and length $section;
308 
309  return make_href($url, $linktext);
310 }
311 
312 
313 # should be sub-classed if extra transformations are needed
314 #
315 # for example a sub-class may search for the given page and return a
316 # relative path to it.
317 #
318 # META: where this functionality should be documented? This module
319 # doesn't have docs section
320 #
321 sub view_seq_link_transform_path {
322  my($self, $page) = @_;
323 
324  # right now the default transform doesn't check whether the link
325  # is not dead (i.e. whether there is a corresponding file.
326  # therefore we don't link L<>'s other than L<http://>
327  # subclass to change the default (and of course add validation)
328 
329  # this is the minimal transformation that will be required if enabled
330  # $page = "$page.html";
331  # $page =~ s|::|/|g;
332  #print "page $page\n";
333  return undef;
334 }
335 
336 
337 sub make_href {
338  my($url, $title) = @_;
339 
340  if (!defined $url) {
341  return defined $title ? "<i>$title</i>" : '';
342  }
343 
344  $title = $url unless defined $title;
345  #print "$url, $title\n";
346  return qq{<a href="$url">$title</a>};
347 }
348 
349 
350 
351 
352 # this code has been borrowed from Pod::Html
353 my $urls = '(' . join ('|',
354  qw{
355  http
356  telnet
357  mailto
358  news
359  gopher
360  file
361  wais
362  ftp
363  } ) . ')';
364 my $ltrs = '\w';
365 my $gunk = '/#~:.?+=&%@!\-';
366 my $punc = '.:!?\-;';
367 my $any = "${ltrs}${gunk}${punc}";
368 
369 sub view_seq_text {
370  my ($self, $text) = @_;
371 
372  unless ($HTML_PROTECT) {
373  for ($text) {
374  s/&/&amp;/g;
375  s/</&lt;/g;
376  s/>/&gt;/g;
377  }
378  }
379 
380  $text =~ s{
381  \b # start at word boundary
382  ( # begin $1 {
383  $urls : # need resource and a colon
384  (?!:) # Ignore File::, among others.
385  [$any] +? # followed by one or more of any valid
386  # character, but be conservative and
387  # take only what you need to....
388  ) # end $1 }
389  (?= # look-ahead non-consumptive assertion
390  [$punc]* # either 0 or more punctuation followed
391  (?: # followed
392  [^$any] # by a non-url char
393  | # or
394  $ # end of the string
395  ) #
396  | # or else
397  $ # then end of the string
398  )
399  }{<a href="$1">$1</a>}igox;
400 
401  return $text;
402 }
403 
404 sub encode {
405  my($self,$text) = @_;
406  require Encode;
407  return Encode::encode("ascii",$text,Encode::FB_XMLCREF());
408 }
409 
410 1;
411 
412 =head1 NAME
413 
414 Pod::POM::View::HTML
415 
416 =head1 DESCRIPTION
417 
418 HTML view of a Pod Object Model.
419 
420 =head1 METHODS
421 
422 =over 4
423 
424 =item C<view($self, $type, $item)>
425 
426 =item C<view_pod($self, $pod)>
427 
428 =item C<view_head1($self, $head1)>
429 
430 =item C<view_head2($self, $head2)>
431 
432 =item C<view_head3($self, $head3)>
433 
434 =item C<view_head4($self, $head4)>
435 
436 =item C<view_over($self, $over)>
437 
438 =item C<view_item($self, $item)>
439 
440 =item C<view_for($self, $for)>
441 
442 =item C<view_begin($self, $begin)>
443 
444 =item C<view_textblock($self, $textblock)>
445 
446 =item C<view_verbatim($self, $verbatim)>
447 
448 =item C<view_meta($self, $meta)>
449 
450 =item C<view_seq_bold($self, $text)>
451 
452 Returns the text of a C<BE<lt>E<gt>> sequence enclosed in a C<E<lt>b<E<gt>> element.
453 
454 =item C<view_seq_italic($self, $text)>
455 
456 Returns the text of a C<IE<lt>E<gt>> sequence enclosed in a C<E<lt>i<E<gt>> element.
457 
458 =item C<view_seq_code($self, $text)>
459 
460 Returns the text of a C<CE<lt>E<gt>> sequence enclosed in a C<E<lt>code<E<gt>> element.
461 
462 =item C<view_seq_file($self, $text)>
463 
464 =item C<view_seq_entity($self, $text)>
465 
466 =item C<view_seq_index($self, $text)>
467 
468 Returns an empty string. Index sequences are suppressed in HTML view.
469 
470 =item C<view_seq_link($self, $text)>
471 
472 =back
473 
474 =head1 AUTHOR
475 
476 Andy Wardley E<lt>abw@kfs.orgE<gt>
477 
478 =head1 COPYRIGHT AND LICENSE
479 
480 Copyright (C) 2000 Andy Wardley. All Rights Reserved.
481 
482 This module is free software; you can redistribute it and/or
483 modify it under the same terms as Perl itself.
484 
485 =cut