File Coverage

blib/lib/Mojito/Model/Link.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1 3     3   16 use strictures 1;
  3         21  
  3         79  
2             package Mojito::Model::Link;
3             {
4             $Mojito::Model::Link::VERSION = '0.24';
5             }
6 3     3   278 use Moo;
  3         7  
  3         19  
7 3     3   2687 use Mojito::Model::Doc;
  0            
  0            
8             use Mojito::Collection::Present;
9             use DateTime;
10             use XML::Atom::SimpleFeed;
11             use Data::Dumper::Concise;
12              
13             with('Mojito::Role::Config');
14              
15             has base_url => ( is => 'rw', );
16              
17             has name_of_page_collection => (
18             is => 'rw',
19             );
20              
21             has db => (is => 'ro', lazy => 1);
22              
23             has doc => (
24             is => 'ro',
25             isa => sub { die "Need a Doc Model object. Have ref($_[0]) instead." unless $_[0]->isa('Mojito::Model::Doc') },
26             lazy => 1,
27             handles => [
28             qw(
29             get_most_recent_docs
30             get_feed_docs
31             get_collections
32             get_collection_pages
33             get_docs_for_month
34             )
35             ],
36             writer => '_build_doc',
37             );
38              
39             =head1 Methods
40              
41             =head2 get_most_recent_link_data
42              
43             Get the recent links data structure - ArrayRef[HashRef]
44              
45             TODO: There's HTML in here, omg.
46              
47             =cut
48              
49             sub get_most_recent_link_data {
50             my ($self) = @_;
51             my $cursor = $self->get_most_recent_docs;
52             return $self->get_link_data($cursor);
53             }
54              
55             =head2 get_feed_link_data
56              
57             Get the data to create links for a particular feed.
58              
59             =cut
60              
61             sub get_feed_link_data {
62             my ($self, $feed) = @_;
63             my $cursor = $self->get_feed_docs($feed);
64             return $self->get_link_data($cursor);
65             }
66              
67             =head2 get_atom_feed
68              
69             Get the data to create links for a particular feed.
70              
71             =cut
72              
73             sub get_atom_feed {
74             my ($self, $feed) = @_;
75             my $cursor = $self->get_feed_docs($feed);
76             my @feed_title = split /_/, $feed;
77             my $feed_title = join ' ', map { ucfirst($_) } @feed_title;
78             my $atom = XML::Atom::SimpleFeed->new(title => $feed_title, id => $feed);
79             while (my $doc = $cursor->next) {
80             my $link = $self->base_url . 'public/page/' . $doc->{'_id'}->value;
81             my $author = $doc->{author} || $self->config->{default_author} || 'Anonymous';
82             my $dt = DateTime->from_epoch( epoch => $doc->{last_modified} );
83             $dt->set_time_zone($self->config->{local_timezone});
84             my $updated = $dt->mdy('/') . ' ' . $dt->hms;
85             $atom->add_entry(
86             title => $doc->{title},
87             'link', => $link,
88             author => $author,
89             id => $doc->{'_id'}->value,
90             updated => $updated,
91             );
92             }
93             return $atom->as_string;
94             }
95              
96             =head2 get_collections_index_link_data
97              
98             Get the data to create links to all the available collections.
99              
100             =cut
101              
102             sub get_collections_index_link_data {
103             my ($self) = @_;
104             my $cursor = $self->get_collections;
105             return $self->get_link_data($cursor);
106             }
107              
108             =head2 get_collection_link_data
109              
110             Get the data to create links to all the documents in a collection.
111              
112             =cut
113              
114             sub get_collection_link_data {
115             my ($self, $collection_id) = @_;
116             my ($name_of_page_collection, $pages) = $self->get_collection_pages($collection_id);
117             # Store this for use later
118             $self->name_of_page_collection($name_of_page_collection);
119             return $self->get_link_data($pages);
120             }
121              
122             =head2 get_link_data
123              
124             Given a MongoDB cursor OR ArrayRef of documents then create the link data.
125              
126             =cut
127              
128             sub get_link_data {
129             my ($self, $cursor) = @_;
130             my $link_data;
131             if ( ref($cursor) eq 'MongoDB::Cursor' ) {
132             while ( my $doc = $cursor->next ) {
133             my $title = $doc->{title}||$doc->{collection_name}||'no title';
134             push @{$link_data}, { id => $doc->{'_id'}->value, title => $title };
135             }
136             }
137             elsif ( ref($cursor) eq 'ARRAY' ) {
138             foreach my $doc (@{$cursor}) {
139             my $title = $doc->{title}||$doc->{collection_name}||'no title';
140             push @{$link_data}, { id => $doc->{'_id'}||$doc->{id}, title => $title };
141             }
142             }
143             else {
144             die "I don't know how to get link data for ", Dumper $cursor;
145             }
146              
147             return $link_data;
148             }
149              
150             =head2 get_recent_links
151              
152             Turn the data into HTML
153             $args should be a HashRef of options
154              
155             =cut
156              
157             sub get_recent_links {
158             my ($self, $args) = @_;
159              
160             # Let's limit the amount of recent links we show
161             # if we've set a limit in our config.
162             $args->{last_link_number} = $self->config->{last_link_number};
163             my $base_url = $self->base_url;
164             my $link_data = $self->get_most_recent_link_data;
165             my $link_title = '<span id="recent_articles_label" style="font-weight: bold;">Recent Articles</span><br />' . "\n";
166             my $links = $self->create_list_of_links($link_data, $args) || "No Documents yet. Get to <a href='${base_url}page'>writing!</a>";
167              
168             return $link_title . $links;
169             }
170              
171             =head2 get_feed_links
172              
173             Get the links for the documents belonging to a particular feed.
174              
175             =cut
176              
177             sub get_feed_links {
178             my ($self, $feed) = @_;
179              
180             my $link_data = $self->get_feed_link_data($feed);
181             my @feed_title = split /_/, $feed;
182             my $feed_title = join ' ', map { ucfirst($_) } @feed_title;
183             my $title = $feed_title . ' Feed';
184             my $link_title = "<span class='feeds' style='font-weight: bold;'>$title</span><br />";
185             my $links = $self->create_list_of_links($link_data, {want_public_link => 1});
186             if ($links) {
187             return $link_title . $links;
188             }
189             else {
190             "The <em>$feed</em> feed is <b>empty</b>";
191             }
192             }
193              
194             =head2 view_selectable_page_list
195              
196             Get the links for the documents belonging to a particular feed.
197              
198             =cut
199              
200             sub view_selectable_page_list {
201             my ($self, $args) = @_;
202              
203             my $base_url = $self->base_url;
204             my $link_data = $self->get_most_recent_link_data;
205             my $list_title = '<span id="selectable_page_list_label" style="font-weight: bold;">Select articles to be part of a collection</span><br />' . "\n";
206             my $list = $self->create_selectable_page_list($link_data, $args) || "No Documents yet. Get to <a href='${base_url}page'>writing!</a>";
207              
208             return $list_title . $list;
209             }
210              
211             =head2 view_sortable_page_list
212              
213             View the pages in a collection, ready to be sorted.
214              
215             =cut
216              
217             sub view_sortable_page_list {
218             my ($self, $args) = (shift, shift);
219              
220             my $base_url = $self->base_url;
221             my $link_data = $self->get_collection_link_data($args->{collection_id});
222             my $name_of_page_collection = $self->name_of_page_collection;
223             my $list_title =<<"EOH";
224             <header id='collections_index' style='font-weight: bold;'>
225             ORDER (drag-n-drop) pages in the collection:
226             <span style='color: darkblue; font-size: 1.33em;'>$name_of_page_collection</i></span>
227             </header>
228             EOH
229             my $list = $self->create_sortable_page_list($link_data, $name_of_page_collection) || "No Documents yet. Get to <a href='${base_url}page'>writing!</a>";
230              
231             return $list_title . $list;
232             }
233              
234             =head2 create_selectable_page_list
235              
236             Given link data (doc id and title) and possibly some $args then create hyperlinks
237              
238             =cut
239              
240             sub create_selectable_page_list {
241             my ($self, $link_data) = (shift, shift);
242              
243             return if !$link_data;
244             my $base_url = $self->base_url;
245             my $list;
246             foreach my $datum (@{$link_data}) {
247             $list .= "<li id='$datum->{id}'>$datum->{title}</li>\n";
248             }
249             $list =<<"EOH";
250             <section id='selectable_page_list'>
251             <form action=${base_url}collect method=POST>
252             <label for="collection_name">Collection name: </label>
253             <input type="text" name="collection_name" id="collection_name" required="required" value="" />
254             <ul>
255             ${list}
256             </ul>
257             <div id="hidden_params"><input type="hidden" name="collected_page_ids" id="collected_page_ids" value="" /></div>
258             <input type=submit name=collect value="Create Collection"/>
259             </form>
260             </section>
261              
262             EOH
263            
264             return $list;
265             }
266              
267             =head2 create_sortable_page_list
268              
269             Create a sortable list of the pages in a collection.
270             This is how we impose order to collection of pages.
271              
272             =cut
273              
274             sub create_sortable_page_list {
275             my ($self, $link_data, $collection_name) = (shift, shift, shift);
276              
277             my $list;
278             foreach my $datum (@{$link_data}) {
279             $list .= "<li id='$datum->{id}'>$datum->{title}</li>\n";
280             }
281             $list =<<"EOH";
282             <section id='sortable'>
283             <form action='' method=POST>
284             <input type="hidden" name="collection_name" id="collection_name" value="${collection_name}" />
285             <ol>
286             ${list}
287             </ol>
288             <div id="hidden_params"><input type="hidden" name="collected_page_ids" id="collected_page_ids" value="" /></div>
289             <input type=submit name=collect value="Order Collection"/>
290             </form>
291             </section>
292              
293             EOH
294            
295             return $list;
296             }
297              
298             =head2 view_collections_index
299              
300             List the existing collections
301              
302             =cut
303              
304             sub view_collections_index {
305             my ($self, $args) = @_;
306              
307             $args->{route} = '/collection/';
308             my $base_url = $self->base_url;
309             my $link_data = $self->get_collections_index_link_data;
310             my $list_title = "<span id='collections_index' style='font-weight: bold;'>Page Collections:</span> <a href='${base_url}collect'>create one</a><br />\n";
311             my $list = $self->create_generic_list_of_links($link_data, $args) || "No Collections yet. Get to <a href='${base_url}collect'>creating them!</a>";
312              
313             return $list_title . $list;
314             }
315              
316             =head2 view_collection_page
317              
318             View a list of links to the pages that make up a collection.
319              
320             =cut
321              
322             sub view_collection_page {
323             my ($self, $args) = @_;
324              
325             my $base_url = $self->base_url;
326             my $link_data = $self->get_collection_link_data($args->{collection_id});
327             my $name_of_page_collection = $self->name_of_page_collection;
328             my $list_title =<<"EOH";
329             <header id='collections_index' style='font-weight: bold;'>
330             <span style='color: darkblue; font-size: 1.33em;'>$name_of_page_collection</i></span>
331             </header>
332             EOH
333              
334             $args->{route} = '/collection/' . $args->{collection_id} . '/page/';
335             $args->{route} = '/public' . $args->{route} if $args->{is_public};
336             $args->{list_style} = 'ordered';
337             my $list = $self->create_generic_list_of_links($link_data, $args) || "No Collections yet. Get to <a href='${base_url}/collect'>creating them!</a>";
338              
339             return $list_title . $list;
340             }
341              
342             =head2 create_list_of_links
343              
344             Given link data (doc id and title) and possibly some $args then create hyperlinks
345              
346             =cut
347              
348             sub create_list_of_links {
349             my ($self, $link_data, $args) = @_;
350              
351             my $base_url = $self->base_url;
352             $base_url .= 'public/' if $args->{want_public_link};
353             my $links;
354             my $i = 1; my $limit = $args->{last_link_number};
355             foreach my $datum (@{$link_data}) {
356             $links .= "<div class='list_of_links'>&middot; <a href=\"${base_url}page/" . $datum->{id} . '">' . $datum->{title} . "</a>";
357             if ($args && $args->{want_delete_link}) {
358             $links .= " | <span style='font-size: 0.88em;'><a href=\"${base_url}page/" . $datum->{id} . '/delete"> delete</a></span>';
359             }
360             $links .= "</div>\n";
361             last if ($limit && ($i == $limit)); $i++;
362             }
363             $links = "<section id='list_of_links'>\n${links}\n</section>" if defined $links;
364             return $links;
365             }
366              
367             =head2 create_generic_list_of_links
368              
369             Given link data (doc id and title) and possibly some $args then create hyperlinks,
370             but in a more general manner than create_list_of_links().
371              
372             Returns array of <a hrefs
373              
374             =cut
375              
376             sub create_generic_list_of_links {
377             my ($self, $link_data, $args) = @_;
378            
379             my $base_url = $self->base_url;
380             my $route = $args->{route}||die 'Need a route to create a generic list of links';
381             # make sure $route doesn't start with a '/'
382             $route =~ s/^\///;
383             # NOTE: We're assuming a route like /page/$id or /collection/$id etc.
384             my $base_href = $base_url . $route;
385             my @links;
386             my $item_number = 1;
387             foreach my $datum (@{$link_data}) {
388             next if not $datum->{id};
389             my $moniker = ($args->{list_style} && $args->{list_style} eq 'ordered') ? "$item_number. " : '&middot; ';
390             push @links, $moniker . "<a href=\"${base_href}" . $datum->{id} . '">' . $datum->{title} . "</a>";
391             $item_number++;
392             }
393             my $links = join "<br />\n", @links;
394             my $return = '<section id="list_of_links">' . $links . '</section>';
395             }
396              
397             sub view_collection_nav {
398             my ($self, $params) = @_;
399            
400             # Obtain focus point.
401             my $presenter = Mojito::Collection::Present->new(
402             config => $self->config,
403             db => $self->db,
404             collection_id => $params->{collection_id},
405             focus_page_id => $params->{page_id},
406             );
407            
408             # Handle public collections
409             my $base_url = $self->base_url;
410             $base_url .= 'public/' if $params->{public};
411              
412             my $next_page_URL = $base_url . $presenter->next_page_route;
413             my $previous_page_URL = $base_url . $presenter->previous_page_route;
414             my $index_page_URL = $base_url . $presenter->index_page_route;
415             my $js = $self->collection_nav_js( $next_page_URL, $previous_page_URL, $index_page_URL);
416             my $nav_fragment =<<"EOH";
417             $js
418             <div style="float:right;">
419             <a accesskey='p' href="${previous_page_URL}" title='[p]'>&lt; &lt; Previous</a> |
420             <a accesskey='i' href="${index_page_URL}" title='[i]'>Index</a> |
421             <a accesskey='n' href="${next_page_URL}" title='[n]'>Next &gt;&gt;</a>
422             </div>
423             EOH
424              
425             return $nav_fragment;
426             }
427              
428             sub collection_nav_js {
429             my ($self, $next_page, $previous_page, $index_page) = @_;
430              
431             my $js =<<"EOJ";
432             <script>
433             function nextSlide() {
434             window.location = '$next_page';
435             }
436            
437             function prevSlide() {
438             window.location = '$previous_page';
439             }
440            
441             function indexSlide() {
442             window.location = '$index_page';
443             }
444            
445             function handleKey(e) {
446             var key;
447             if (e == null) {
448             // IE
449             key = event.keyCode
450             }
451             else {
452             // Mozilla
453             if (e.altKey || e.ctrlKey) {
454             return true
455             }
456             key = e.which
457             }
458             switch(key) {
459             case 8: prevSlide(); break
460             case 13: nextSlide(); break
461             case 32: nextSlide(); break
462             case 105: indexSlide(); break
463             case 110: nextSlide(); break
464             case 112: prevSlide(); break
465             default: //xxx(e.which)
466             }
467             }
468              
469             document.onkeypress = handleKey
470             </script>
471              
472             EOJ
473             return $js
474             }
475              
476             =head2 BUILD
477              
478             Create the handler objects
479              
480             =cut
481              
482             sub BUILD {
483             my $self = shift;
484             my $constructor_args_href = shift;
485              
486             # pass the options into the subclasses
487             $self->_build_doc(Mojito::Model::Doc->new($constructor_args_href));
488             }
489              
490             1