blob: eba3dbd5aadf129ab9a65cd9e7234852b333eb08 [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
Akrond512ea62019-10-24 15:50:04 +0200166 my $html = '<ul class="nav nav-'.$realm.'">'."\n";
Akron41a190a2019-10-16 18:01:02 +0200167
168 # Embed all link tags
169 foreach (@$items) {
170
171 my ($active, $url) = 0;
172
173 # There is a fragment!
174 if (index($_->{id}, '#') == 0) {
175
176 my $part_scope = scalar($scope);
177 $part_scope =~ s!\/([^\/]+)$!!;
178 my $page = $1;
179 my $id = $_->{id};
180 $id =~ s/^#//;
181
Akrond512ea62019-10-24 15:50:04 +0200182 $url = $c->url_with($realm, scope => $part_scope, page => $page);
183
184 # Canonicalize (for empty scopes)
185 $url->path->canonicalize;
Akron41a190a2019-10-16 18:01:02 +0200186 $url->fragment($id);
187 }
188
189 # There is no fragment
190 else {
191
192 # The item is active
193 if ($c->stash('page') && $c->stash('page') eq $_->{id}) {
194 $active = 1;
195 };
196
197 # Generate url with query parameter inheritance
Akrond512ea62019-10-24 15:50:04 +0200198 $url = $c->url_with($realm, scope => $scope, page => $_->{id});
Akron41a190a2019-10-16 18:01:02 +0200199
200 # Canonicalize (for empty scopes)
201 $url->path->canonicalize;
Akron9490e3b2019-10-17 12:26:29 +0200202 $url->fragment('page-top');
Akron41a190a2019-10-16 18:01:02 +0200203 };
204
205 my @classes;
206 push(@classes, $_->{'class'}) if $_->{'class'};
207 push(@classes, 'active') if $active;
208
Akron41a190a2019-10-16 18:01:02 +0200209 # New list item
210 $html .= '<li';
211 if (@classes) {
212 $html .= ' class="' . join(' ', @classes) . '"';
213 };
214 $html .= '>';
215
216 # Translate title
217 my $title = $c->loc('Nav_' . $_->{id}, $_->{title});
218
219 # Generate link
220 $html .= $c->link_to($title, $url);
221
222 # Set sub entries
223 if ($_->{items} && ref($_->{items}) eq 'ARRAY') {
224 $html .= "\n";
225 my $subscope = $scope ? scalar($scope) . '/' . $_->{id} : $_->{id};
Akrond512ea62019-10-24 15:50:04 +0200226 $html .= $c->navigation($realm, $subscope, $_->{items});
Akron41a190a2019-10-16 18:01:02 +0200227 $html .= "</li>\n";
228 }
229 else {
230 $html .= "</li>\n";
231 };
232 };
233 return $html . "</ul>\n";
234 }
235 );
236
237
238 # Create helper for queries in the tutorial
239 $mojo->helper(
240 doc_query => sub {
241 my ($c, $ql, $q, %param) = @_;
242
243 # Query is not supported in the corpus
244 if ($q =~ s/^\*\*\s*//) {
245 # Escape query for html embedding
246 $q = xml_escape $q;
247
248 return b(
249 '<pre class="query tutorial unsupported">' .
250 "<code>$q</code>" .
251 '<span title="' . $c->loc('notAvailInCorpus') . '">*</span>' .
252 '</pre>');
253 };
254
255 # Escape query for html embedding
256 $q = xml_escape $q;
257
258 # Return tag
259 b('<pre class="query tutorial" ' .
260 qq!data-query="$q" data-query-cutoff="! .
261 ($param{cutoff} ? 1 : 0) .
262 '"' .
263 qq! data-query-language="$ql">! .
264 '<code>' . $q . '</code>' .
265 '</pre>'
266 );
267 }
268 );
269
Akronf7ec4442019-10-27 20:01:05 +0100270 # Set a navigation list to a realm
271 $mojo->helper(
272 'navi.set' => sub {
273 my $c = shift;
274 my $realm = shift;
275 my $list = shift;
276
277 $navi->{$realm} = $list;
278 }
279 );
280
Akron59992122019-10-29 11:28:45 +0100281 # Add an item to the realm
Akronf7ec4442019-10-27 20:01:05 +0100282 $mojo->helper(
283 'navi.add' => sub {
284 my $c = shift;
285 my $realm = shift;
286 my $navi_realm = ($navi->{$realm} //= []);
287 my $title = shift;
288 my $id = shift;
289
290 push @$navi_realm, {
291 title => $title,
292 id => $id
293 }
294 }
295 );
Akron59992122019-10-29 11:28:45 +0100296
297 # Check for existence
298 $mojo->helper(
299 'navi.exists' => sub {
300 my $c = shift;
301 my $realm = shift;
302 unless (exists $navi->{$realm}) {
303 return 0 ;
304 };
305 return 0 unless ref $navi->{$realm} && @{$navi->{$realm}} > 0;
306 return 1;
307 }
308 );
Akron41a190a2019-10-16 18:01:02 +0200309}
310
3111;
312
313
314
315__END__
316
317=pod
318
319=encoding utf8
320
321=head1 NAME
322
323Kalamar::Plugin::KalamarHelpers
324
325
326=head1 DESCRIPTION
327
328L<Kalamar::Plugin::KalamarHelpers> makes Kalamar specific
329helpers for Mojolicious available.
330
331
332=head1 HELPERS
333
Akron9490e3b2019-10-17 12:26:29 +0200334=head2 embedded_link_to
Akron41a190a2019-10-16 18:01:02 +0200335
336 %# In templates
Akron3cfa26d2019-10-24 15:17:34 +0200337 %= embedded_link_to 'doc','Kalamar', 'korap', 'kalamar'
Akron41a190a2019-10-16 18:01:02 +0200338
Akron3cfa26d2019-10-24 15:17:34 +0200339Create a link to the documentation. Accepts a realm, a title, a scope, and a page.
Akron41a190a2019-10-16 18:01:02 +0200340
341
Akron9490e3b2019-10-17 12:26:29 +0200342=head2 ext_link_to
Akron41a190a2019-10-16 18:01:02 +0200343
344 %# In templates
Akron9490e3b2019-10-17 12:26:29 +0200345 %= ext_link_to 'GitHub', "https://github.com/KorAP/Koral"
Akron41a190a2019-10-16 18:01:02 +0200346
347Creates a link to an external page, that will be opened in the top frame,
Akron9490e3b2019-10-17 12:26:29 +0200348in case it's in an embedded frame.
Akron41a190a2019-10-16 18:01:02 +0200349
350=head2 doc_uc
351
352 %# In templates
353 %= doc_uc
354
355Generates an C<Under Construction> notification.
356
357
358=head2 doc_opener
359
360Currently not used.
361
362
Akrond512ea62019-10-24 15:50:04 +0200363=head2 navigation
Akron41a190a2019-10-16 18:01:02 +0200364
Akrond512ea62019-10-24 15:50:04 +0200365Returns an HTML representation of a navigation structure
Akron41a190a2019-10-16 18:01:02 +0200366based on active navigation items.
367
368
369=head2 doc_query
370
371 %# In templates
372 %= doc_query poliqarp => 'Baum'
373
374Creates an interactive query view for documentation purposes.
375
376
377=head1 COPYRIGHT AND LICENSE
378
379Copyright (C) 2015-2019, L<IDS Mannheim|http://www.ids-mannheim.de/>
380Author: L<Nils Diewald|http://nils-diewald.de/>
381
382Kalamar is developed as part of the L<KorAP|http://korap.ids-mannheim.de/>
383Corpus Analysis Platform at the
384L<Leibniz Institute for the German Language (IDS)|http://ids-mannheim.de/>,
385member of the
hebasta21b7baf2019-12-16 10:32:43 +0100386L<Leibniz-Gemeinschaft|http://www.leibniz-gemeinschaft.de>
Akron41a190a2019-10-16 18:01:02 +0200387and supported by the L<KobRA|http://www.kobra.tu-dortmund.de> project,
388funded by the
389L<Federal Ministry of Education and Research (BMBF)|http://www.bmbf.de/en/>.
390
391Kalamar is free software published under the
392L<BSD-2 License|https://raw.githubusercontent.com/KorAP/Kalamar/master/LICENSE>.
393
394=cut