File Coverage

blib/lib/Blatte/HTML.pm
Criterion Covered Total %
statement 106 106 100.0
branch 38 40 95.0
condition 17 18 94.4
subroutine 15 15 100.0
pod 2 2 100.0
total 178 181 98.3


line stmt bran cond sub pod time code
1 3     3   61252 use strict;
  3         9  
  3         668  
2              
3             package Blatte::HTML::Element;
4              
5             sub new {
6 8     8   16 my $class = shift;
7 8         58 bless [@_], $class;
8             }
9              
10 36     36   130 sub name { $_[0]->[0] }
11              
12 8     8   29 sub attrs { $_[0]->[1] }
13              
14             sub content {
15 6     6   10 my $self = shift;
16 6         36 @$self[2..$#$self];
17             }
18              
19             package Blatte::HTML;
20              
21             BEGIN {
22 3     3   129 @Blatte::HTML::builtins = qw($html_bool_yes $html_bool_no
23             $html_p_yes $html_p_no
24             $html_ent_yes $html_ent_no
25             $a $abbr $acronym $address $applet $area $b
26             $base $basefont $bdo $big $blockquote $body $br
27             $button $caption $center $cite $code $col
28             $colgroup $dd $del $dfn $dir $div $dl $dt $em
29             $fieldset $font $form $frame $frameset $h1 $h2
30             $h3 $h4 $h5 $h6 $head $hr $html $i $iframe $img
31             $input $ins $isindex $kbd $label $legend $li
32             $link $map $menu $meta $noframes $noscript
33             $object $ol $optgroup $option $p $param $pre $q
34             $s $samp $script $select $small $span $strike
35             $strong $style $sub $sup $table $tbody $td
36             $textarea $tfoot $th $thead $title $tr $tt $u
37             $ul $var);
38             }
39              
40 3     3   19 use vars (qw(@ISA @EXPORT @EXPORT_OK $VERSION), @Blatte::HTML::builtins);
  3         9  
  3         2681  
41              
42 3     3   31 use Exporter;
  3         5  
  3         221  
43              
44             @ISA = qw(Exporter);
45              
46             @EXPORT = @Blatte::HTML::builtins;
47             @EXPORT_OK = qw(make_start_tag render);
48              
49             $VERSION = '0.9';
50              
51 3     3   16 use Blatte;
  3         6  
  3         94  
52 3     3   2903 use HTML::Entities;
  3         25059  
  3         306  
53 3     3   2645 use HTML::Tagset;
  3         4337  
  3         110  
54 3     3   2721 use Symbol;
  3         3094  
  3         11607  
55              
56             my $_html_bool_yes = gensym();
57             my $_html_bool_no = gensym();
58              
59             $html_bool_yes = sub { $_html_bool_yes };
60             $html_bool_no = sub { $_html_bool_no };
61              
62             $html_p_yes = sub { new Blatte::HTML::Element('_p', 1, @_[1 .. $#_]) };
63             $html_p_no = sub { new Blatte::HTML::Element('_p', 0, @_[1 .. $#_]) };
64             $html_ent_yes = sub { new Blatte::HTML::Element('_ent', 1, @_[1 .. $#_]) };
65             $html_ent_no = sub { new Blatte::HTML::Element('_ent', 0, @_[1 .. $#_]) };
66              
67             $a = sub { new Blatte::HTML::Element('a', @_) };
68             $abbr = sub { new Blatte::HTML::Element('abbr', @_) };
69             $acronym = sub { new Blatte::HTML::Element('acronym', @_) };
70             $address = sub { new Blatte::HTML::Element('address', @_) };
71             $applet = sub { new Blatte::HTML::Element('applet', @_) };
72             $area = sub { new Blatte::HTML::Element('area', @_) };
73             $b = sub { new Blatte::HTML::Element('b', @_) };
74             $base = sub { new Blatte::HTML::Element('base', @_) };
75             $basefont = sub { new Blatte::HTML::Element('basefont', @_) };
76             $bdo = sub { new Blatte::HTML::Element('bdo', @_) };
77             $big = sub { new Blatte::HTML::Element('big', @_) };
78             $blockquote = sub { new Blatte::HTML::Element('blockquote', @_) };
79             $body = sub { new Blatte::HTML::Element('body', @_) };
80             $br = sub { new Blatte::HTML::Element('br', @_) };
81             $button = sub { new Blatte::HTML::Element('button', @_) };
82             $caption = sub { new Blatte::HTML::Element('caption', @_) };
83             $center = sub { new Blatte::HTML::Element('center', @_) };
84             $cite = sub { new Blatte::HTML::Element('cite', @_) };
85             $code = sub { new Blatte::HTML::Element('code', @_) };
86             $col = sub { new Blatte::HTML::Element('col', @_) };
87             $colgroup = sub { new Blatte::HTML::Element('colgroup', @_) };
88             $dd = sub { new Blatte::HTML::Element('dd', @_) };
89             $del = sub { new Blatte::HTML::Element('del', @_) };
90             $dfn = sub { new Blatte::HTML::Element('dfn', @_) };
91             $dir = sub { new Blatte::HTML::Element('dir', @_) };
92             $div = sub { new Blatte::HTML::Element('div', @_) };
93             $dl = sub { new Blatte::HTML::Element('dl', @_) };
94             $dt = sub { new Blatte::HTML::Element('dt', @_) };
95             $em = sub { new Blatte::HTML::Element('em', @_) };
96             $fieldset = sub { new Blatte::HTML::Element('fieldset', @_) };
97             $font = sub { new Blatte::HTML::Element('font', @_) };
98             $form = sub { new Blatte::HTML::Element('form', @_) };
99             $frame = sub { new Blatte::HTML::Element('frame', @_) };
100             $frameset = sub { new Blatte::HTML::Element('frameset', @_) };
101             $h1 = sub { new Blatte::HTML::Element('h1', @_) };
102             $h2 = sub { new Blatte::HTML::Element('h2', @_) };
103             $h3 = sub { new Blatte::HTML::Element('h3', @_) };
104             $h4 = sub { new Blatte::HTML::Element('h4', @_) };
105             $h5 = sub { new Blatte::HTML::Element('h5', @_) };
106             $h6 = sub { new Blatte::HTML::Element('h6', @_) };
107             $head = sub { new Blatte::HTML::Element('head', @_) };
108             $hr = sub { new Blatte::HTML::Element('hr', @_) };
109             $html = sub { new Blatte::HTML::Element('html', @_) };
110             $i = sub { new Blatte::HTML::Element('i', @_) };
111             $iframe = sub { new Blatte::HTML::Element('iframe', @_) };
112             $img = sub { new Blatte::HTML::Element('img', @_) };
113             $input = sub { new Blatte::HTML::Element('input', @_) };
114             $ins = sub { new Blatte::HTML::Element('ins', @_) };
115             $isindex = sub { new Blatte::HTML::Element('isindex', @_) };
116             $kbd = sub { new Blatte::HTML::Element('kbd', @_) };
117             $label = sub { new Blatte::HTML::Element('label', @_) };
118             $legend = sub { new Blatte::HTML::Element('legend', @_) };
119             $li = sub { new Blatte::HTML::Element('li', @_) };
120             $link = sub { new Blatte::HTML::Element('link', @_) };
121             $map = sub { new Blatte::HTML::Element('map', @_) };
122             $menu = sub { new Blatte::HTML::Element('menu', @_) };
123             $meta = sub { new Blatte::HTML::Element('meta', @_) };
124             $noframes = sub { new Blatte::HTML::Element('noframes', @_) };
125             $noscript = sub { new Blatte::HTML::Element('noscript', @_) };
126             $object = sub { new Blatte::HTML::Element('object', @_) };
127             $ol = sub { new Blatte::HTML::Element('ol', @_) };
128             $optgroup = sub { new Blatte::HTML::Element('optgroup', @_) };
129             $option = sub { new Blatte::HTML::Element('option', @_) };
130             $p = sub { new Blatte::HTML::Element('p', @_) };
131             $param = sub { new Blatte::HTML::Element('param', @_) };
132             $pre = sub { new Blatte::HTML::Element('pre', @_) };
133             $q = sub { new Blatte::HTML::Element('q', @_) };
134             $s = sub { new Blatte::HTML::Element('s', @_) };
135             $samp = sub { new Blatte::HTML::Element('samp', @_) };
136             $script = sub { new Blatte::HTML::Element('script', @_) };
137             $select = sub { new Blatte::HTML::Element('select', @_) };
138             $small = sub { new Blatte::HTML::Element('small', @_) };
139             $span = sub { new Blatte::HTML::Element('span', @_) };
140             $strike = sub { new Blatte::HTML::Element('strike', @_) };
141             $strong = sub { new Blatte::HTML::Element('strong', @_) };
142             $style = sub { new Blatte::HTML::Element('style', @_) };
143             $sub = sub { new Blatte::HTML::Element('sub', @_) };
144             $sup = sub { new Blatte::HTML::Element('sup', @_) };
145             $table = sub { new Blatte::HTML::Element('table', @_) };
146             $tbody = sub { new Blatte::HTML::Element('tbody', @_) };
147             $td = sub { new Blatte::HTML::Element('td', @_) };
148             $textarea = sub { new Blatte::HTML::Element('textarea', @_) };
149             $tfoot = sub { new Blatte::HTML::Element('tfoot', @_) };
150             $th = sub { new Blatte::HTML::Element('th', @_) };
151             $thead = sub { new Blatte::HTML::Element('thead', @_) };
152             $title = sub { new Blatte::HTML::Element('title', @_) };
153             $tr = sub { new Blatte::HTML::Element('tr', @_) };
154             $tt = sub { new Blatte::HTML::Element('tt', @_) };
155             $u = sub { new Blatte::HTML::Element('u', @_) };
156             $ul = sub { new Blatte::HTML::Element('ul', @_) };
157             $var = sub { new Blatte::HTML::Element('var', @_) };
158              
159             # Hmm, why did HTML::Tagset neglect to do this?
160             my %p_closure_barriers = map { ($_ => 1) } @HTML::Tagset::p_closure_barriers;
161              
162             sub make_start_tag {
163 6     6 1 9 my $obj = shift;
164 6         27 my $result = $obj->name();
165 6         15 my $attrs = $obj->attrs();
166 6         23 foreach my $attr (keys %$attrs) {
167 3         6 my $val = $attrs->{$attr};
168 3 100       14 if ($val ne $_html_bool_no) {
169 2 100       8 if ($val eq $_html_bool_yes) {
170 1         6 $result .= " $attr";
171             } else {
172 1         5 $result .= sprintf(' %s="%s"',
173             $attr,
174             &encode_entities(&Blatte::flatten($val, '')));
175             }
176             }
177             }
178 6         67 "<$result>";
179             }
180              
181             sub render {
182 10     10 1 3364 my($val, $render_cb) = @_;
183 10         18 my $do_p = 1;
184 10         15 my $do_entities = 1;
185 10         14 my @stack;
186             my $traverse_cb;
187             $traverse_cb = sub {
188 26     26   669 my($ws, $obj) = @_;
189              
190 26         37 my $old_do_p = $do_p;
191 26         31 my $old_do_entities = $do_entities;
192              
193 26         96 my $obj_is_html_elt = &UNIVERSAL::isa($obj, 'Blatte::HTML::Element');
194              
195 26   100     90 my $obj_is__p = ($obj_is_html_elt && ($obj->name() eq '_p'));
196 26   100     74 my $obj_is__ent = ($obj_is_html_elt && ($obj->name() eq '_ent'));
197 26   100     115 my $obj_is_control = ($obj_is__p || $obj_is__ent);
198              
199 26 100       73 if ($obj_is__p) {
    100          
200 1         6 $do_p = $obj->attrs();
201             } elsif ($obj_is__ent) {
202 1         4 $do_entities = $obj->attrs();
203             }
204              
205 26   100     70 my $obj_is_p = ($obj_is_html_elt && ($obj->name() eq 'p'));
206 26   66     173 my $newpar = ($do_p &&
207             ($obj_is_p || (defined($ws) && ($ws =~ /\n.*\n/))));
208              
209 26         30 my $close_needed;
210              
211 26 100       53 if ($newpar) {
212 5         16 for (my $i = $#stack; $i >= 0; --$i) {
213 3         4 my $elt = $stack[$i];
214 3         5 my $name = $elt->[0];
215 3 50       9 last if ($p_closure_barriers{$name});
216 3 100       10 if ($name eq 'p') {
217 1         1 $close_needed = $i;
218 1         2 last;
219             }
220             }
221              
222 5 100       12 if (defined($close_needed)) {
223 1         4 for (my $i = $#stack; $i >= $close_needed; --$i) {
224 2         7 my $elt = $stack[$i];
225 2         4 my $name = $elt->[0];
226 2         9 &$render_cb("");
227             }
228              
229 1 50       7 splice(@stack, $close_needed, 1) if $obj_is_p;
230             }
231             }
232              
233 26 100       86 &$render_cb($ws) if defined($ws);
234              
235 26 100       94 if ($newpar) {
236 5 100       13 if (defined($close_needed)) {
    100          
237 1         5 for (my $i = $close_needed; $i <= $#stack; ++$i) {
238 2         6 my $elt = $stack[$i];
239 2         5 my($name, $tag) = @$elt;
240 2         5 &$render_cb($tag);
241             }
242             } elsif (!$obj_is_p) {
243 3         5 my $tag = '

';

244 3         6 &$render_cb($tag);
245 3         14 push(@stack, ['p', $tag]);
246             }
247             }
248              
249 26 100       49 if ($obj_is_html_elt) {
250 8         14 my $tag;
251             my $name;
252              
253 8 100       20 unless ($obj_is_control) {
254 6         15 $tag = &make_start_tag($obj);
255 6         20 &$render_cb($tag);
256 6         22 $name = $obj->name();
257             }
258              
259 8 100 100     47 if ($obj_is_control || !$HTML::Tagset::emptyElement{$name}) {
260 6         7 my $pair;
261              
262 6 100       17 unless ($obj_is_control) {
263 4         11 $pair = [$name, $tag];
264 4         9 push(@stack, $pair);
265             }
266              
267 6         21 &Blatte::traverse([$obj->content()], $traverse_cb);
268              
269 6 100       57 unless ($obj_is_control) {
270 4         21 for (my $i = $#stack; $i >= 0; --$i) {
271 5         10 my $elt = $stack[$i];
272 5 100       51 if ($elt eq $pair) {
273 4         96 for (my $j = $#stack; $j >= $i; --$j) {
274 5         11 my $elt2 = $stack[$j];
275 5         10 my $name2 = $elt2->[0];
276 5         64 &$render_cb("");
277             }
278 4         25 splice(@stack, $i);
279 4         12 last;
280             }
281             }
282             }
283             }
284             } else {
285 18 100       63 &$render_cb($do_entities ? &encode_entities($obj) : $obj);
286             }
287              
288 26         211 $do_p = $old_do_p;
289 26         94 $do_entities = $old_do_entities;
290 10         82 };
291 10         50 &Blatte::traverse($val, $traverse_cb);
292             }
293              
294             1;
295              
296             __END__