Added new article
[sdlgit/SDL-Site.git] / code / HTML / Zoom.pm
1 package HTML::Zoom;
2
3 use strict;
4 use warnings FATAL => 'all';
5 use Carp qw(confess);
6
7 use HTML::Zoom::EventFilter;
8 use HTML::Zoom::SelectorParser;
9 use HTML::Zoom::ActionBuilder;
10 use HTML::Zoom::Parser::BuiltIn;
11
12 sub new {
13   my $proto = shift;
14   my $class = ref($proto) || $proto;
15   bless({}, $class);
16 }
17
18 sub _clone_with {
19   my ($self, %clone) = @_;
20   bless({ %$self, %clone }, ref($self));
21 }
22
23 sub from_string {
24   my $new = shift->new;
25   $new->{source_html} = shift;
26   $new;
27 }
28
29 sub from_fh {
30   my $new = shift->new;
31   my $fh = $_[0];
32   $new->{source_html} = do { local $/; <$fh> || die "from_fh: $!" };
33   $new;
34 }
35
36 sub with_selectors {
37   my $self = shift;
38   my $pairs = [];
39   while (my @spec = splice(@_, 0, 2)) {
40     push(
41       @$pairs,
42       HTML::Zoom::EventFilter->build_selector_pair(@spec)
43     );
44   }
45   $self->_clone_with(
46     _selector_handler => HTML::Zoom::EventFilter->selector_handler($pairs)
47   );
48 }
49
50 sub render_to {
51   my ($self, $out) = @_;
52   $self->_clone_with(
53     _emitter => HTML::Zoom::EventFilter->standard_emitter($out)
54   )->render;
55 }
56
57 sub render {
58   my ($self) = @_;
59   my $s_h = $self->{_selector_handler};
60   $s_h->set_next($self->{_emitter});
61   HTML::Zoom::Parser::BuiltIn::_hacky_tag_parser(
62     $self->{source_html}, sub { $s_h->call(@_) }
63   );
64   $self;
65 }
66
67 =head1 NAME
68
69 HTML::Zoom - Lightweight CSS selector based HTML templating
70
71 =head1 SYNOPSIS
72
73   use HTML::Zoom;
74
75   my $html = <<HTML;
76   <html>
77     <head>
78       <title>Hello people</title>
79     </head>
80     <body>
81       <h1 id="greeting">Placeholder</h1>
82       <div id="list">
83         <span>
84           <p>Name: <span class="name">Bob</span></p>
85           <p>Age: <span class="age">23</span></p>
86         </span>
87         <hr class="between" />
88       </div>
89     </body>
90   </html>
91   HTML
92
93   HTML::Zoom->from_string($html)
94             ->add_selectors(
95                 'title, #greeting' => 'Hello world & dog!',
96                 '#list' => [
97                   { '.name' => 'Matt',
98                     '.age' => 26
99                   },
100                   { '.name' => 'Mark',
101                     '.age' => '0x29'
102                   },
103                   { '.name' => 'Epitaph',
104                     '.age' => '<redacted>'
105                   },
106                   'span:odd p' => { -add_class => 'alt' },
107                 ]
108               )
109             ->stream_to(\*STDOUT)
110             ->render;
111
112 will print -
113
114   <html>
115     <head>
116       <title>Hello world &amp; dog!</title>
117     </head>
118     <body>
119       <h1 id="greeting">Hello world &amp; dog!</h1>
120       <div id="list">
121         <span>
122           <p>Name: <span class="name">Matt</span></p>
123           <p>Age: <span class="age">26</span></p>
124         <span>
125         <hr class="between" />
126         <span>
127           <p class="alt">Name: <span class="name">Mark</span></p>
128           <p class="alt">Age: <span class="age">0x29</span></p>
129         <span>
130         <hr class="between" />
131         <span>
132           <p>Name: <span class="name">Epitaph</span></p>
133           <p>Age: <span class="age">&lt;redacted&gt;</span></p>
134         <span>
135       </div>
136     </body>
137   </html>
138
139 Using a layout -
140
141   <html>
142     <head>
143       <title>default title</title>
144     </head>
145     <body>
146       <img src="/logo.jpg" />
147     </body>
148   </html>
149
150 =head1 SELECTORS
151
152 http://docs.jquery.com/Selectors
153
154 =cut
155
156 1;