line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Template::Lace::Renderer; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
722
|
use Moo; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
11
|
|
4
|
1
|
|
|
1
|
|
617
|
use Scalar::Util; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
1434
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
has [qw(model dom components)] => (is=>'ro', required=>1); |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
sub call { |
9
|
4
|
|
|
4
|
1
|
25
|
my ($self, $proto, @args) = @_; |
10
|
4
|
100
|
100
|
|
|
33
|
if(ref($proto)||'' eq 'CODE') { |
|
|
50
|
|
|
|
|
|
11
|
1
|
|
|
|
|
11
|
return $proto->($self->model, $self->dom, @args); |
12
|
|
|
|
|
|
|
} elsif($proto) { |
13
|
3
|
|
|
|
|
24
|
return $self->model->$proto($self->dom, @args); |
14
|
|
|
|
|
|
|
} |
15
|
|
|
|
|
|
|
} |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
sub call_at { |
18
|
0
|
|
|
0
|
1
|
0
|
my ($self, $css, $proto, @args) = @_; |
19
|
0
|
|
|
|
|
0
|
my $dom = $self->dom->at($css); |
20
|
0
|
0
|
0
|
|
|
0
|
if(ref($proto)||'' eq 'CODE') { |
|
|
0
|
|
|
|
|
|
21
|
0
|
|
|
|
|
0
|
return $proto->($self->model, $dom, @args); |
22
|
|
|
|
|
|
|
} elsif($proto) { |
23
|
0
|
|
|
|
|
0
|
return $self->model->$proto($dom, @args); |
24
|
|
|
|
|
|
|
} |
25
|
|
|
|
|
|
|
} |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
sub render { |
28
|
2
|
|
|
2
|
0
|
9
|
my $self = shift; |
29
|
2
|
|
|
|
|
9
|
my $rendered_dom = $self->get_processed_dom |
30
|
|
|
|
|
|
|
->to_string; |
31
|
2
|
|
|
|
|
1445
|
return $rendered_dom; |
32
|
|
|
|
|
|
|
} |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
sub get_processed_dom { |
35
|
6
|
|
|
6
|
0
|
17
|
my $self = shift; |
36
|
6
|
|
|
|
|
24
|
my $dom = $self->dom; |
37
|
6
|
|
|
|
|
32
|
$self->process_components($dom); |
38
|
6
|
100
|
|
|
|
1368
|
$self->model->process_dom($dom) |
39
|
|
|
|
|
|
|
if $self->model->can('process_dom'); |
40
|
6
|
|
|
|
|
15537
|
return $dom; |
41
|
|
|
|
|
|
|
} |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
sub process_components { |
44
|
6
|
|
|
6
|
0
|
20
|
my ($self, $dom) = @_; |
45
|
6
|
|
|
|
|
12
|
my @ordered_keys = @{$self->components->ordered_component_keys}; |
|
6
|
|
|
|
|
41
|
|
46
|
6
|
|
|
|
|
18
|
my %constructed_components = (); |
47
|
6
|
|
|
|
|
19
|
foreach my $id(@ordered_keys) { |
48
|
7
|
50
|
|
|
|
3525
|
next unless $self->components->handlers->{$id}; # might skip if 'static' handler |
49
|
7
|
100
|
|
|
|
47
|
next unless my $local_dom = $dom->at("[uuid='$id']"); |
50
|
|
|
|
|
|
|
my $constructed_component = $self->process_component( |
51
|
|
|
|
|
|
|
$local_dom, |
52
|
|
|
|
|
|
|
$self->components->handlers->{$id}, |
53
|
|
|
|
|
|
|
\%constructed_components, |
54
|
5
|
|
|
|
|
6648
|
%{$self->components->component_info->{$id}}); |
|
5
|
|
|
|
|
55
|
|
55
|
5
|
50
|
|
|
|
44
|
$constructed_components{$id} = $constructed_component |
56
|
|
|
|
|
|
|
if $constructed_component; |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
# Now post process.. We do this so that parents can have access to |
59
|
|
|
|
|
|
|
# children for transforming dom. |
60
|
6
|
|
|
|
|
26
|
foreach my $id(@ordered_keys) { |
61
|
7
|
100
|
|
|
|
9198
|
next unless $constructed_components{$id}; |
62
|
5
|
|
|
|
|
32
|
my $processed_component = $constructed_components{$id}->get_processed_dom; |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
#=head1 comment |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
# Move all the scripts, styles and links to the head area |
67
|
|
|
|
|
|
|
# TODO this probably doesn't work if the stuff is in a component |
68
|
|
|
|
|
|
|
# inside a component. |
69
|
|
|
|
|
|
|
$processed_component->find('link:not(head link)')->each(sub { |
70
|
0
|
0
|
0
|
0
|
|
0
|
return unless $_->attr('id') || $_->attr('href'); |
71
|
0
|
|
|
|
|
0
|
$dom->append_link_uniquely($_); |
72
|
0
|
|
|
|
|
0
|
$_->remove; |
73
|
5
|
|
|
|
|
188
|
}); # href |
74
|
|
|
|
|
|
|
$processed_component->find('style:not(head style)')->each(sub { |
75
|
3
|
50
|
|
3
|
|
1983
|
return unless $_->attr('id'); |
76
|
3
|
|
|
|
|
116
|
$dom->append_style_uniquely($_); |
77
|
3
|
|
|
|
|
30
|
$_->remove; |
78
|
5
|
|
|
|
|
2265
|
}); #id |
79
|
|
|
|
|
|
|
$processed_component->find('script:not(head script)')->each(sub { |
80
|
0
|
|
|
0
|
|
0
|
my ($e, $num) = @_; |
81
|
0
|
0
|
0
|
|
|
0
|
return unless $e->attr('id') || $e->attr('src'); |
82
|
0
|
|
|
|
|
0
|
$dom->append_script_uniquely($e); |
83
|
0
|
|
|
|
|
0
|
$_->remove; |
84
|
5
|
|
|
|
|
1233
|
}); #id or src |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
#=cut |
87
|
|
|
|
|
|
|
|
88
|
5
|
|
|
|
|
1965
|
$dom->at("[uuid='$id']")->replace($processed_component); |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
sub prepare_component_attrs { |
93
|
5
|
|
|
5
|
0
|
28
|
my ($self, $dom, $model, %component_info) = @_; |
94
|
|
|
|
|
|
|
my %attrs = ( |
95
|
5
|
|
|
|
|
13
|
$self->process_attrs($model, $dom, %{$component_info{attrs}}), |
|
5
|
|
|
|
|
34
|
|
96
|
|
|
|
|
|
|
content=>$dom->content, |
97
|
|
|
|
|
|
|
model=>$model); |
98
|
5
|
|
|
|
|
933
|
return %attrs; |
99
|
|
|
|
|
|
|
} |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
sub process_component { |
102
|
5
|
|
|
5
|
0
|
37
|
my ($self, $dom, $component, $constructed_components, %component_info) = @_; |
103
|
5
|
|
|
|
|
35
|
my %attrs = $self->prepare_component_attrs($dom, $self->model, %component_info); |
104
|
5
|
50
|
|
|
|
31
|
if(my $container_id = $component_info{current_container_id}) { |
105
|
|
|
|
|
|
|
# Its possible if the compoent was a 'on_component_add' type that |
106
|
|
|
|
|
|
|
# its been removed from the DOM and a Child might still have it as |
107
|
|
|
|
|
|
|
# a container by mistake. Possible a TODO to have a better idea. |
108
|
|
|
|
|
|
|
$attrs{container} = $constructed_components->{$container_id}->model |
109
|
5
|
100
|
|
|
|
30
|
if $constructed_components->{$container_id}; |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
|
112
|
5
|
50
|
|
|
|
31
|
if(Scalar::Util::blessed $component) { |
|
|
0
|
|
|
|
|
|
113
|
5
|
|
|
|
|
11
|
my $constructed_component; |
114
|
5
|
100
|
|
|
|
20
|
if($attrs{container}) { |
115
|
2
|
50
|
|
|
|
21
|
if($attrs{container}->can('create_child')) { |
116
|
0
|
|
|
|
|
0
|
$constructed_component = $attrs{container}->create_child($component, %attrs); |
117
|
|
|
|
|
|
|
} else { |
118
|
2
|
|
|
|
|
16
|
$constructed_component = $component->create(%attrs); |
119
|
|
|
|
|
|
|
$attrs{container}->add_child($constructed_component) if |
120
|
2
|
50
|
|
|
|
27
|
$attrs{container}->can('add_child'); |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
} else { |
123
|
3
|
|
|
|
|
28
|
$constructed_component = $component->create(%attrs); |
124
|
|
|
|
|
|
|
} |
125
|
5
|
|
|
|
|
37
|
return $constructed_component; |
126
|
|
|
|
|
|
|
} elsif(ref($component) eq 'CODE') { |
127
|
0
|
|
|
|
|
0
|
die "Component not an object"; |
128
|
|
|
|
|
|
|
#my $new_dom = $component->($dom->content, %attrs); |
129
|
|
|
|
|
|
|
#warn $new_dom; |
130
|
|
|
|
|
|
|
#$dom->replace($new_dom); |
131
|
|
|
|
|
|
|
#warn $dom; |
132
|
|
|
|
|
|
|
#return; |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
sub process_attrs { |
137
|
7
|
|
|
7
|
0
|
45
|
my ($self, $ctx, $dom, %attrs) = @_; |
138
|
|
|
|
|
|
|
return map { |
139
|
7
|
|
|
|
|
34
|
my $proto = $attrs{$_}; |
|
24
|
|
|
|
|
68
|
|
140
|
24
|
100
|
|
|
|
97
|
my $value = ref($proto) ? $proto->($ctx, $dom) : $proto; |
141
|
24
|
|
|
|
|
2671
|
$_ => $value; |
142
|
|
|
|
|
|
|
} keys %attrs; |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
1; |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
=head1 NAME |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
Template::Lace::Renderer |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
=head1 SYNOPSIS |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
TBD |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
=head1 DESCRIPTION |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
Renderer for the model. Not really end user aimed. See L<Template::Lace> |
158
|
|
|
|
|
|
|
for main overview. |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
=head1 METHODS |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
This class defines the following public methods |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
=head2 call |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
Allows you to have the renderer 'call' a method into the model, with the current |
167
|
|
|
|
|
|
|
DOM. Takes either a coderef or a string (that must be the name of a method in the |
168
|
|
|
|
|
|
|
model. Example: |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
$renderer->call(sub { |
171
|
|
|
|
|
|
|
my ($model, $dom) = @_; |
172
|
|
|
|
|
|
|
$model->add_debug($dom); |
173
|
|
|
|
|
|
|
}, @args); |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
$renderer->call('add_debug', @args); |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
Are both the same as |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
$renderer |
180
|
|
|
|
|
|
|
->model |
181
|
|
|
|
|
|
|
->add_debug($renderer->dom, @args); |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
You might find this is a useful shortcut (or not). |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
=head2 call_at |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
Basically similar to L</call> except allows you to specify a CSS match to |
188
|
|
|
|
|
|
|
set the DOM. |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
$renderer->call_at('#debug','add_debug', @args); |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
Is basically a shortcut for: |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
my $dom = $renderer->dom->at('#debug); |
195
|
|
|
|
|
|
|
$renderer->model->add_debug($dom, @args); |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
=head1 SEE ALSO |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
L<Template::Lace>. |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
=head1 AUTHOR |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
Please See L<Template::Lace> for authorship and contributor information. |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
Please see L<Template::Lace> for copyright and license information. |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
=cut |