Commit | Line | Data |
e30ed59d |
1 | package App::IdiotBox; |
2 | |
3 | use Web::Simple __PACKAGE__; |
4 | use Method::Signatures::Simple; |
d7497a23 |
5 | use FindBin; |
6 | use HTML::Zoom; |
7 | |
8 | { |
9 | package App::IdiotBox::Announcement; |
10 | |
11 | sub made_at { shift->{made_at} } |
12 | sub bucket { shift->{bucket} } |
13 | sub video_count { shift->{video_count} } |
14 | |
15 | package App::IdiotBox::Bucket; |
16 | |
17 | sub slug { shift->{slug} } |
18 | sub name { shift->{name} } |
d9702c6d |
19 | sub video_count { |
20 | exists $_[0]->{video_count} |
21 | ? $_[0]->{video_count} |
22 | : $_[0]->{videos}->count |
23 | } |
71fd1550 |
24 | sub videos { shift->{videos} } |
25 | |
26 | package App::IdiotBox::Video; |
27 | |
28 | sub slug { shift->{slug} } |
29 | sub name { shift->{name} } |
30 | sub author { shift->{author} } |
31 | sub details { shift->{details} } |
32 | sub bucket { shift->{bucket} } |
d7497a23 |
33 | } |
34 | |
35 | default_config( |
36 | template_dir => $FindBin::Bin.'/../share/html' |
37 | ); |
e30ed59d |
38 | |
39 | dispatch { |
40 | sub (/) { $self->show_front_page }, |
41 | subdispatch sub (/*/...) { |
42 | my $bucket = $self->buckets->get({ slug => $_[1] }); |
43 | [ |
44 | sub (/) { |
45 | $self->show_bucket($bucket) |
46 | }, |
47 | sub (/*) { |
d7497a23 |
48 | $self->show_video($bucket->videos->get({ slug => $_[1] })); |
e30ed59d |
49 | } |
50 | ] |
51 | } |
52 | }; |
53 | |
d7497a23 |
54 | method recent_announcements { $self->{recent_announcements} } |
55 | |
e30ed59d |
56 | method show_front_page { |
57 | my $ann = $self->recent_announcements; |
58 | $self->html_response( |
59 | front_page => [ |
d7497a23 |
60 | '#announcement-list' => [ |
61 | -repeat_content => { |
62 | repeat_for => $ann->map(sub { [ |
63 | '.fill-bucket-name' => [ |
64 | -replace_content => { replace_with => $_->bucket->name } |
65 | ], |
66 | '.fill-bucket-link' => [ |
67 | -set_attribute => { name => 'href', value => $_->bucket->slug.'/' } |
68 | ], |
69 | '.fill-new-videos' => [ |
70 | -replace_content => { replace_with => $_->video_count } |
71 | ], |
72 | '.fill-total-videos' => [ |
73 | -replace_content => { replace_with => $_->bucket->video_count } |
74 | ], |
75 | ] })->as_stream |
e30ed59d |
76 | } |
d7497a23 |
77 | ] |
e30ed59d |
78 | ] |
79 | ); |
80 | } |
81 | |
d7497a23 |
82 | method show_bucket ($bucket) { |
83 | $self->html_response(bucket => [ |
84 | '.fill-bucket-name' => [ |
85 | -replace_content => { replace_with => $bucket->name } |
86 | ], |
87 | '#video-list' => [ |
88 | -repeat_content => { |
89 | repeat_for => $bucket->videos->map(sub { [ |
90 | '.fill-video-name' => [ |
91 | -replace_content => { replace_with => $_->name } |
92 | ], |
93 | '.fill-video-author' => [ |
94 | -replace_content => { replace_with => $_->author } |
95 | ], |
96 | '.fill-video-link' => [ |
97 | -set_attribute => { |
98 | name => 'href', value => $_->slug.'/' |
99 | } |
100 | ], |
101 | ] })->as_stream |
102 | } |
103 | ] |
104 | ]); |
105 | } |
106 | |
107 | method show_video ($video) { |
108 | $self->html_response(video => [ |
109 | '.fill-video-name' => [ |
110 | -replace_content => { replace_with => $video->name } |
111 | ], |
112 | '.fill-author-name' => [ |
113 | -replace_content => { replace_with => $video->author } |
114 | ], |
115 | '.fill-bucket-link' => [ |
116 | -set_attribute => { name => 'href', value => '../' } |
117 | ], |
118 | '.fill-bucket-name' => [ |
119 | -replace_content => { replace_with => $video->bucket->name } |
120 | ], |
121 | '.fill-video-details' => [ |
122 | -replace_content => { replace_with => $video->details } |
123 | ] |
124 | ]); |
125 | } |
126 | |
e30ed59d |
127 | method html_response ($template_name, $selectors) { |
d7497a23 |
128 | my $io = $self->_zoom_for($template_name => $selectors)->as_readable_fh; |
e30ed59d |
129 | return [ 200, [ 'Content-Type' => 'text/html' ], $io ] |
130 | } |
131 | |
d7497a23 |
132 | method _template_filename_for ($name) { |
133 | $self->{config}{template_dir}.'/'.$name.'.html'; |
134 | } |
135 | |
e30ed59d |
136 | method _layout_zoom { |
d7497a23 |
137 | $self->{layout_zoom} ||= HTML::Zoom->from_file( |
138 | $self->_template_filename_for('layout') |
e30ed59d |
139 | ) |
140 | } |
141 | |
142 | method _zoom_for ($template_name, $selectors) { |
143 | ($self->{zoom_for_template}{$template_name} ||= do { |
144 | my @body; |
d7497a23 |
145 | HTML::Zoom->from_file( |
146 | $self->_template_filename_for($template_name) |
e30ed59d |
147 | ) |
148 | ->with_selectors( |
d7497a23 |
149 | '#main-content' => [ |
150 | -capture_events => { into => \@body } |
151 | ] |
e30ed59d |
152 | ) |
d7497a23 |
153 | ->run; |
154 | $self->_layout_zoom->with_selectors( |
155 | '#main-content' => [ |
156 | -replace_content_events => { replace_with => \@body } |
157 | ] |
158 | )->to_zoom; |
159 | })->with_selectors($selectors) |
e30ed59d |
160 | } |
161 | |
162 | 1; |