word: prevent infinite loops on invalid data
[sheet.git] / word.plp
1 <(common.inc.plp)><:
2
3 if ($Request and $Request =~ m{\A([^/]+)}) {
4         my $page = "word/$1.plp";
5         utf8::downgrade($page); # unicode filename breaks contents encoding
6         if (-e $page) {
7                 Include $page;
8                 exit;
9         }
10 }
11
12 my $lang = $get{lang} || 'en';
13 my $wordlist = "data/wordlist.$lang.inc.pl";
14 my $limit = $get{v} // (exists $get{v} ? 4 : 3);
15
16 Html({
17         title => 'words cheat sheet',
18         version => '1.0',
19         description => "Visual words",
20         keywords => [qw'
21                 language
22         '],
23         data => [$wordlist],
24         raw => (exists $get{q} && <<'EOT')
25 <style>
26 .gallery figure {
27         grid-row: span 1 !important;
28         grid-column: span 1 !important;
29 }
30 .gallery figcaption {
31         /* keep hover position */
32         right: 50%;
33         bottom: 50%;
34         transform: translate(50%, 50%);
35         /* hide */
36         visibility: hidden;
37         font-size: 0 !important;
38 }
39 .gallery figure:active > figcaption {
40         visibility: visible;
41         font-size: 175% !important;
42 }
43 </style>
44 EOT
45                 . <<'EOT',
46 <style>
47 body {
48         margin: 8px 1px;
49 }
50 </style>
51 EOT
52 });
53
54 if (exists $get{debug}) {
55         say '<style>';
56         include 'word-debug.css';
57         say '</style>';
58 }
59 :>
60 <h1>Words</h1>
61
62 <p>
63 Under construction.
64 Zie ook <a href="/dieren">dieren</a>.
65 <a href="?q">Omit translations</a> to test.
66 </p>
67
68 <:
69 my $table = do $wordlist or die $@ // $!;
70
71 sub showimg {
72         my ($id, $name) = @_;
73         my ($imgname) = $name =~ m{^([^/]+)};
74         $name =~ s/\w{4} [^aoeuiyc\W] [rl]?+ \K (?= [^aoeuiy\W] [rl]? [aoeuiy] \w)/&shy;/gx;
75         ($name, my @morenames) = split m{/}, $name;
76         $name =~ s{\( ([^/]+) \)}{<small>$1</small>}x;
77         $name .= " <small>($_)</small>" for @morenames;
78         my $hidden = $name =~ s/\?$//;
79         $name = "<q>$name</q>" if $name =~ s/\?$//;
80         $name = "<figcaption>$name</figcaption>";
81
82         if ($id and -e (my $img = "data/word/en/$id.jpg")) {
83                 $name .= sprintf '<img src="/%s" alt="%s" />', $img, $imgname;
84         }
85         return sprintf '<figure%s>%s</figure>', $hidden && !exists $get{v} && ' hidden', $name;
86 }
87
88 sub printimgs {
89         say '<ul>';
90         for my $row (@_) {
91                 my ($id, $level, $title) = split /:/, $row, 3;
92                 $id or die "empty reference"; # assertion to prevent loops
93                 my @type;
94                 push @type, 'parent' if defined $table->{$id};
95                 push @type, 'large'  if $level =~ s/c$//;
96                 push @type, 'level'.($level || 0);
97                 printf '<li%s>', @type ? sprintf ' class="%s"', join ' ', @type : '';
98                 print showimg($id, $title) if $level <= $limit;
99                 printimgs(@{$_}) for $table->{$id} // ();
100                 print '</li>';
101         }
102         say '</ul>';
103 }
104
105 say '<section class="gallery">';
106 if (exists $get{q}) {
107         my @rows;
108         if ($Request) {
109                 my @query = $Request;
110                 while (@query) {
111                         push @rows, grep { (split /:/)[1] <= $limit } @query;
112                         s/:.*// for @query;
113                         @query = map {$_ ? @{$_} : ()} @{$table}{@query};
114                 }
115         }
116         else {
117                 @rows = map {ref ? @$_ : $_} values %{$table}; # flatten categories
118         }
119         @rows = sort { rand <=> .5 } @rows;
120         $table = {};
121         printimgs(@rows);
122 }
123 else {
124         printimgs($Request || $table->{''}->[0]);
125 }
126 say '</section>';