blob: d1ad11832399f8ba0e049dce0a466d61c650b552 [file] [log] [blame]
Akron41a190a2019-10-16 18:01:02 +02001package Kalamar::Plugin::KalamarPages;
2use Mojo::Base 'Mojolicious::Plugin';
3use Mojo::JSON qw/decode_json true false/;
4use Mojo::ByteStream 'b';
5use Mojo::Util qw/xml_escape deprecated/;
6
Akronf7ec4442019-10-27 20:01:05 +01007our $navi = {};
Akron41a190a2019-10-16 18:01:02 +02008
9# TODO:
10# Add documentation plugin to programmatically
11# create documentation navigation as a content_block
12# so custom routes to custom templates can easily
13# be configured
14sub register {
15 my ($plugin, $mojo) = @_;
16
17 # Documentation link
18 # TODO: Support opener mechanism, so the link will open the embedded
19 # documentation in case it's not there.
20 $mojo->helper(
Akron9490e3b2019-10-17 12:26:29 +020021 embedded_link_to => sub {
Akron41a190a2019-10-16 18:01:02 +020022 my $c = shift;
Akron3cfa26d2019-10-24 15:17:34 +020023
24 # The embedded link now expects at least 3 parameters:
25 # - The realm, which is identical to the named route
26 # - The title of the link
27 # - An optional scope, which is a first level path for navigation
28 # - The page to link to (accepting a fragment)
29 my $realm = shift;
Akron41a190a2019-10-16 18:01:02 +020030 my $title = shift;
31 my $page = pop;
32 my $scope = shift;
33
34 ($page, my $fragment) = split '#', $page;
35
Akron3cfa26d2019-10-24 15:17:34 +020036 my $url = $c->url_with($realm, page => $page, scope => $scope);
Akron41a190a2019-10-16 18:01:02 +020037 $url->fragment($fragment) if $fragment;
Akron254fe212019-10-24 14:33:28 +020038 $url->path->canonicalize;
Akron41a190a2019-10-16 18:01:02 +020039
40 return $c->link_to(
41 $title,
42 $url,
Akron9490e3b2019-10-17 12:26:29 +020043 class => 'embedded-link'
Akron41a190a2019-10-16 18:01:02 +020044 );
45 }
46 );
47
Akron9490e3b2019-10-17 12:26:29 +020048 # DEPRECATED: 2019-10-17
Akron41a190a2019-10-16 18:01:02 +020049 $mojo->helper(
Akron9490e3b2019-10-17 12:26:29 +020050 doc_link_to => sub {
51 my $c = shift;
52 deprecated 'Deprecated "doc_link_to" in favor of "embedded_link_to"';
Akron3cfa26d2019-10-24 15:17:34 +020053 return $c->embedded_link_to('doc', @_)
Akron9490e3b2019-10-17 12:26:29 +020054 }
55 );
56
57 # Link to an external page
58 $mojo->helper(
59 ext_link_to => sub {
Akron41a190a2019-10-16 18:01:02 +020060 my $c = shift;
61 return $c->link_to(@_, target => '_top');
62 }
63 );
64
Akron9490e3b2019-10-17 12:26:29 +020065 # DEPRECATED: 2019-10-17
66 $mojo->helper(
67 doc_ext_link_to => sub {
68 my $c = shift;
69 deprecated 'Deprecated "doc_ext_link_to" in favor of "ext_link_to"';
70 return $c->ext_link_to(@_);
71 }
72 );
Akron41a190a2019-10-16 18:01:02 +020073
Akron9490e3b2019-10-17 12:26:29 +020074 # Page alert - Under Construction!
75 $mojo->helper(
76 under_construction => sub {
77 my $c = shift;
78 return $c->tag('p', $c->loc('underConstruction', 'Under Construction!'));
79 }
80 );
81
82 # Page alert - Under Construction!
83 # DEPRECATED: 2019-10-17
Akron41a190a2019-10-16 18:01:02 +020084 $mojo->helper(
85 doc_uc => sub {
86 my $c = shift;
Akron9490e3b2019-10-17 12:26:29 +020087 deprecated 'Deprecated "doc_uc" in favor of "under_construction"';
88 return $c->under_construction
89 }
90 );
91
92 # Page title helper
93 $mojo->helper(
94 page_title => sub {
95 my $c = shift;
96 return $c->tag('h2' => (id => 'page-top') => $c->stash('title'))
Akron41a190a2019-10-16 18:01:02 +020097 }
98 );
99
100 $mojo->helper(
101 doc_opener => sub {
102 my $c = shift;
103 my $cb = pop;
104 my $page = pop;
105 my $scope = shift;
106 my $url;
107 if ($page) {
Akrond512ea62019-10-24 15:50:04 +0200108 $url = $c->url_with('doc', scope => $scope, page => $page);
Akron41a190a2019-10-16 18:01:02 +0200109 $url->path->canonicalize;
110 }
111 else {
112 $url = $c->url_for('doc_start');
113 };
114 return $c->link_to($cb->($c), $url);
115 }
116 );
117
118
Akrond512ea62019-10-24 15:50:04 +0200119 # DEPRECATED: 2019-10-24
Akron41a190a2019-10-16 18:01:02 +0200120 $mojo->helper(
121 'doc.url' => sub {
Akrond512ea62019-10-24 15:50:04 +0200122 deprecated 'Deprecated "doc->url" in favor of direct usage with "url_with"';
Akron41a190a2019-10-16 18:01:02 +0200123 my $c = shift;
124 my $page = pop;
125 my $scope = shift;
Akron41a190a2019-10-16 18:01:02 +0200126 return $c->url_with(
Akron254fe212019-10-24 14:33:28 +0200127 'doc',
128 page => $page,
129 scope => $scope
Akron41a190a2019-10-16 18:01:02 +0200130 );
131 }
132 );
133
134 # Documentation navigation helper
Akrond512ea62019-10-24 15:50:04 +0200135 # DEPRECATED: 2019-10-24
Akron41a190a2019-10-16 18:01:02 +0200136 $mojo->helper(
137 doc_navi => sub {
Akrond512ea62019-10-24 15:50:04 +0200138 deprecated 'Deprecated "docnavi" in favor of "navigation"';
Akron41a190a2019-10-16 18:01:02 +0200139 my $c = shift;
Akrond512ea62019-10-24 15:50:04 +0200140 return $c->navigation('doc', @_)
141 }
142 );
143
144 # Navigation helper
145 $mojo->helper(
146 'navigation' => sub {
147 my $c = shift;
148 my $realm = shift;
Akron41a190a2019-10-16 18:01:02 +0200149 my $items = pop;
150 my $scope = shift;
151
Akronf7ec4442019-10-27 20:01:05 +0100152 # Take items from central list
153 unless ($items) {
154 $items = $navi->{$realm};
Akron59992122019-10-29 11:28:45 +0100155
156 # Realm has no entries
157 return '' unless $items;
158 }
159
160 # Set realm
161 else {
162 $navi->{$realm} = $items;
Akronf7ec4442019-10-27 20:01:05 +0100163 };
164
Akron41a190a2019-10-16 18:01:02 +0200165 # Create unordered list
Akron64833cc2021-09-08 17:19:27 +0200166 my $html = '<ul class="nav nav-'.$realm;
167 my $men_active = 0;
168 my $item_str = '';
Akron41a190a2019-10-16 18:01:02 +0200169
170 # Embed all link tags
171 foreach (@$items) {
172
173 my ($active, $url) = 0;
174
175 # There is a fragment!
176 if (index($_->{id}, '#') == 0) {
177
178 my $part_scope = scalar($scope);
179 $part_scope =~ s!\/([^\/]+)$!!;
180 my $page = $1;
181 my $id = $_->{id};
182 $id =~ s/^#//;
183
Akrond512ea62019-10-24 15:50:04 +0200184 $url = $c->url_with($realm, scope => $part_scope, page => $page);
185
186 # Canonicalize (for empty scopes)
187 $url->path->canonicalize;
Akron41a190a2019-10-16 18:01:02 +0200188 $url->fragment($id);
189 }
190
191 # There is no fragment
192 else {
193
194 # The item is active
195 if ($c->stash('page') && $c->stash('page') eq $_->{id}) {
196 $active = 1;
Akron64833cc2021-09-08 17:19:27 +0200197 $men_active = 1;
Akron41a190a2019-10-16 18:01:02 +0200198 };
199
200 # Generate url with query parameter inheritance
Akrond512ea62019-10-24 15:50:04 +0200201 $url = $c->url_with($realm, scope => $scope, page => $_->{id});
Akron41a190a2019-10-16 18:01:02 +0200202
203 # Canonicalize (for empty scopes)
204 $url->path->canonicalize;
Akron9490e3b2019-10-17 12:26:29 +0200205 $url->fragment('page-top');
Akron41a190a2019-10-16 18:01:02 +0200206 };
207
208 my @classes;
209 push(@classes, $_->{'class'}) if $_->{'class'};
210 push(@classes, 'active') if $active;
211
Akron41a190a2019-10-16 18:01:02 +0200212 # New list item
Akron64833cc2021-09-08 17:19:27 +0200213 $item_str .= '<li';
Akron41a190a2019-10-16 18:01:02 +0200214 if (@classes) {
Akron64833cc2021-09-08 17:19:27 +0200215 $item_str .= ' class="' . join(' ', @classes) . '"';
Akron41a190a2019-10-16 18:01:02 +0200216 };
Akron64833cc2021-09-08 17:19:27 +0200217 $item_str .= '>';
Akron41a190a2019-10-16 18:01:02 +0200218
219 # Translate title
220 my $title = $c->loc('Nav_' . $_->{id}, $_->{title});
221
222 # Generate link
Akron64833cc2021-09-08 17:19:27 +0200223 $item_str .= $c->link_to($title, $url);
Akron41a190a2019-10-16 18:01:02 +0200224
225 # Set sub entries
226 if ($_->{items} && ref($_->{items}) eq 'ARRAY') {
Akron64833cc2021-09-08 17:19:27 +0200227 $item_str .= "\n";
Akron41a190a2019-10-16 18:01:02 +0200228 my $subscope = $scope ? scalar($scope) . '/' . $_->{id} : $_->{id};
Akron64833cc2021-09-08 17:19:27 +0200229 $item_str .= $c->navigation($realm, $subscope, $_->{items});
230 $item_str .= "</li>\n";
Akron41a190a2019-10-16 18:01:02 +0200231 }
232 else {
Akron64833cc2021-09-08 17:19:27 +0200233 $item_str .= "</li>\n";
Akron41a190a2019-10-16 18:01:02 +0200234 };
235 };
Akron64833cc2021-09-08 17:19:27 +0200236
237 $html .= ' active' if $men_active;
238 $html .= '">'."\n";
239 $html .= $item_str;
Akron41a190a2019-10-16 18:01:02 +0200240 return $html . "</ul>\n";
241 }
242 );
243
244
245 # Create helper for queries in the tutorial
246 $mojo->helper(
247 doc_query => sub {
248 my ($c, $ql, $q, %param) = @_;
249
250 # Query is not supported in the corpus
251 if ($q =~ s/^\*\*\s*//) {
252 # Escape query for html embedding
253 $q = xml_escape $q;
254
255 return b(
256 '<pre class="query tutorial unsupported">' .
257 "<code>$q</code>" .
258 '<span title="' . $c->loc('notAvailInCorpus') . '">*</span>' .
259 '</pre>');
260 };
261
262 # Escape query for html embedding
263 $q = xml_escape $q;
264
265 # Return tag
266 b('<pre class="query tutorial" ' .
267 qq!data-query="$q" data-query-cutoff="! .
268 ($param{cutoff} ? 1 : 0) .
269 '"' .
270 qq! data-query-language="$ql">! .
271 '<code>' . $q . '</code>' .
272 '</pre>'
273 );
274 }
275 );
276
Akronf7ec4442019-10-27 20:01:05 +0100277 # Set a navigation list to a realm
278 $mojo->helper(
279 'navi.set' => sub {
280 my $c = shift;
281 my $realm = shift;
282 my $list = shift;
283
284 $navi->{$realm} = $list;
285 }
286 );
287
Akron59992122019-10-29 11:28:45 +0100288 # Add an item to the realm
Akronf7ec4442019-10-27 20:01:05 +0100289 $mojo->helper(
290 'navi.add' => sub {
291 my $c = shift;
292 my $realm = shift;
293 my $navi_realm = ($navi->{$realm} //= []);
294 my $title = shift;
295 my $id = shift;
296
297 push @$navi_realm, {
298 title => $title,
299 id => $id
300 }
301 }
302 );
Akron59992122019-10-29 11:28:45 +0100303
304 # Check for existence
305 $mojo->helper(
306 'navi.exists' => sub {
307 my $c = shift;
308 my $realm = shift;
309 unless (exists $navi->{$realm}) {
310 return 0 ;
311 };
312 return 0 unless ref $navi->{$realm} && @{$navi->{$realm}} > 0;
313 return 1;
314 }
315 );
Akron41a190a2019-10-16 18:01:02 +0200316}
317
3181;
319
320
321
322__END__
323
324=pod
325
326=encoding utf8
327
328=head1 NAME
329
330Kalamar::Plugin::KalamarHelpers
331
332
333=head1 DESCRIPTION
334
335L<Kalamar::Plugin::KalamarHelpers> makes Kalamar specific
336helpers for Mojolicious available.
337
338
339=head1 HELPERS
340
Akron9490e3b2019-10-17 12:26:29 +0200341=head2 embedded_link_to
Akron41a190a2019-10-16 18:01:02 +0200342
343 %# In templates
Marc Kupietzfcadda62021-09-08 09:06:25 +0200344 %= embedded_link_to 'doc','Kalamar', 'development', 'kalamar'
Akron41a190a2019-10-16 18:01:02 +0200345
Akron3cfa26d2019-10-24 15:17:34 +0200346Create a link to the documentation. Accepts a realm, a title, a scope, and a page.
Akron41a190a2019-10-16 18:01:02 +0200347
348
Akron9490e3b2019-10-17 12:26:29 +0200349=head2 ext_link_to
Akron41a190a2019-10-16 18:01:02 +0200350
351 %# In templates
Akron9490e3b2019-10-17 12:26:29 +0200352 %= ext_link_to 'GitHub', "https://github.com/KorAP/Koral"
Akron41a190a2019-10-16 18:01:02 +0200353
354Creates a link to an external page, that will be opened in the top frame,
Akron9490e3b2019-10-17 12:26:29 +0200355in case it's in an embedded frame.
Akron41a190a2019-10-16 18:01:02 +0200356
357=head2 doc_uc
358
359 %# In templates
360 %= doc_uc
361
362Generates an C<Under Construction> notification.
363
364
365=head2 doc_opener
366
367Currently not used.
368
369
Akrond512ea62019-10-24 15:50:04 +0200370=head2 navigation
Akron41a190a2019-10-16 18:01:02 +0200371
Akrond512ea62019-10-24 15:50:04 +0200372Returns an HTML representation of a navigation structure
Akron41a190a2019-10-16 18:01:02 +0200373based on active navigation items.
374
375
376=head2 doc_query
377
378 %# In templates
379 %= doc_query poliqarp => 'Baum'
380
381Creates an interactive query view for documentation purposes.
382
383
384=head1 COPYRIGHT AND LICENSE
385
386Copyright (C) 2015-2019, L<IDS Mannheim|http://www.ids-mannheim.de/>
387Author: L<Nils Diewald|http://nils-diewald.de/>
388
389Kalamar is developed as part of the L<KorAP|http://korap.ids-mannheim.de/>
390Corpus Analysis Platform at the
391L<Leibniz Institute for the German Language (IDS)|http://ids-mannheim.de/>,
392member of the
hebasta21b7baf2019-12-16 10:32:43 +0100393L<Leibniz-Gemeinschaft|http://www.leibniz-gemeinschaft.de>
Akron41a190a2019-10-16 18:01:02 +0200394and supported by the L<KobRA|http://www.kobra.tu-dortmund.de> project,
395funded by the
396L<Federal Ministry of Education and Research (BMBF)|http://www.bmbf.de/en/>.
397
398Kalamar is free software published under the
399L<BSD-2 License|https://raw.githubusercontent.com/KorAP/Kalamar/master/LICENSE>.
400
401=cut