Commit | Line | Data |
9d159224 |
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 & dog!</title> |
117 | </head> |
118 | <body> |
119 | <h1 id="greeting">Hello world & 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"><redacted></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; |