]>
Commit | Line | Data |
---|---|---|
4772671f TC |
1 | package BSE::Formatter; |
2 | use strict; | |
d794b180 | 3 | use DevHelp::HTML; |
6a8a205a | 4 | use Carp 'confess'; |
4772671f TC |
5 | |
6 | use base 'DevHelp::Formatter'; | |
7 | ||
def1a923 TC |
8 | my $pop_nameid = 'AAAAAA'; |
9 | ||
4772671f | 10 | sub new { |
c5286ebe | 11 | my $class = shift; |
4772671f | 12 | |
c5286ebe TC |
13 | my (%opts) = |
14 | ( | |
15 | images => [], | |
16 | files => [], | |
17 | abs_urls => 0, | |
18 | acts => {}, | |
19 | @_ | |
20 | ); | |
4772671f | 21 | |
c5286ebe | 22 | my $self = $class->SUPER::new; |
4772671f | 23 | |
c5286ebe TC |
24 | $self->{gen} = $opts{gen}; |
25 | $self->{acts} = $opts{acts}; | |
26 | $self->{articles} = $opts{articles}; | |
27 | $self->{abs_urls} = $opts{abs_urls}; | |
28 | my $dummy; | |
29 | $self->{auto_images} = $opts{auto_images} || \$dummy; | |
30 | $self->{images} = $opts{images}; | |
31 | $self->{files} = $opts{files}; | |
32 | $self->{templater} = $opts{templater}; | |
33 | ||
34 | my $cfg = $self->{gen}->{cfg}; | |
62533efa TC |
35 | if ($cfg->entry('html', 'mbcs', 0)) { |
36 | $self->{conservative_escape} = 1; | |
37 | } | |
38 | ||
4772671f TC |
39 | $self; |
40 | } | |
41 | ||
daee3409 | 42 | sub _image { |
41f10371 | 43 | my ($self, $im, $align, $url, $style) = @_; |
daee3409 TC |
44 | |
45 | my $text = qq!<img src="/images/$im->{image}" width="$im->{width}"! | |
46 | . qq! height="$im->{height}" alt="! . escape_html($im->{alt}).'"' | |
47 | . qq! border="0"!; | |
48 | $text .= qq! align="$align"! if $align && $align ne 'center'; | |
41f10371 | 49 | if ($style) { |
015362d9 | 50 | if ($style =~ /^\d/) { |
41f10371 TC |
51 | $text .= qq! style="padding: $style"!; |
52 | } | |
015362d9 TC |
53 | elsif ($style =~ /^\w+$/) { |
54 | $text .= qq! class="$style"!; | |
55 | } | |
41f10371 TC |
56 | else { |
57 | $text .= qq! style="$style"!; | |
58 | } | |
59 | } | |
daee3409 TC |
60 | $text .= qq! />!; |
61 | $text = qq!<div align="center">$text</div>! | |
62 | if $align && $align eq 'center'; | |
12b22d44 TC |
63 | # the text in $url would have been HTML escaped already, the url |
64 | # in the image record hasn't been | |
daee3409 | 65 | if (!$url && $im->{url}) { |
12b22d44 | 66 | $url = escape_html($im->{url}); |
daee3409 TC |
67 | } |
68 | if ($url) { | |
12b22d44 | 69 | $text = qq!<a href="$url">$text</a>!; |
daee3409 TC |
70 | } |
71 | ||
72 | return $text; | |
73 | } | |
74 | ||
75 | sub gimage { | |
76 | my ($self, $args) = @_; | |
77 | ||
41f10371 | 78 | my ($name, $align, $url, $style) = split /\|/, $args, 4; |
daee3409 TC |
79 | my $im = $self->{gen}->get_gimage($name); |
80 | if ($im) { | |
81 | $self->_image($im, $align, $url); | |
82 | } | |
83 | else { | |
84 | return ''; | |
85 | } | |
86 | } | |
87 | ||
4772671f TC |
88 | sub image { |
89 | my ($self, $args) = @_; | |
90 | ||
91 | my $images = $self->{images}; | |
41f10371 | 92 | my ($index, $align, $url, $style) = split /\|/, $args, 4; |
4772671f TC |
93 | my $text = ''; |
94 | my $im; | |
95 | if ($index =~ /^\d+$/) { | |
96 | if ($index >=1 && $index <= @$images) { | |
97 | $im = $images->[$index-1]; | |
dbe0477f | 98 | ${$self->{auto_images}} = 0; |
4772671f TC |
99 | } |
100 | } | |
101 | elsif ($index =~ /^[a-z]\w*$/i){ | |
102 | # scan the names | |
103 | for my $image (@$images) { | |
104 | if ($image->{name} && lc $image->{name} eq lc $index) { | |
105 | $im = $image; | |
106 | last; | |
107 | } | |
108 | } | |
109 | } | |
110 | if ($im) { | |
41f10371 | 111 | return $self->_image($im, $align, $url, $style); |
daee3409 TC |
112 | } |
113 | else { | |
114 | return ''; | |
4772671f | 115 | } |
4772671f TC |
116 | } |
117 | ||
118 | sub embed { | |
119 | my ($self, $name, $templateid, $maxdepth) = @_; | |
120 | ||
121 | $self->{gen}->_embed_low($self->{acts}, $self->{articles}, $name, | |
5d88571c | 122 | $templateid, $maxdepth, $self->{templater}); |
4772671f TC |
123 | } |
124 | ||
00dd8d82 TC |
125 | sub _get_article { |
126 | my ($self, $id, $error) = @_; | |
127 | ||
6a8a205a TC |
128 | my $cfg = $self->{gen}->{cfg} |
129 | or confess "cfg not set in acts"; | |
130 | my $dispid; | |
131 | if ($id =~ /^\d+$/) { | |
132 | $dispid = $id; | |
133 | } | |
134 | else { | |
135 | # try to find it in the config | |
136 | my $work = $cfg->entry('articles', $id); | |
137 | unless ($work) { | |
00dd8d82 TC |
138 | $$error = "** No article name '".escape_html($id)."' in the [articles] section of bse.cfg **"; |
139 | return; | |
6a8a205a TC |
140 | } |
141 | $dispid = "$id ($work)"; | |
142 | $id = $work; | |
143 | } | |
144 | my $art = $self->{articles}->getByPkey($id); | |
145 | unless ($art) { | |
00dd8d82 TC |
146 | $$error = "** Cannot find article id $dispid **"; |
147 | return; | |
6a8a205a TC |
148 | } |
149 | ||
00dd8d82 TC |
150 | return $art; |
151 | } | |
152 | ||
153 | sub doclink { | |
8f84f3f1 | 154 | my ($self, $id, $title, $target, $type) = @_; |
00dd8d82 TC |
155 | |
156 | my $error; | |
157 | my $art = $self->_get_article($id, \$error) | |
158 | or return $error; | |
159 | ||
160 | my $cfg = $self->{gen}->{cfg} | |
161 | or confess "cfg not set in acts"; | |
162 | ||
6a8a205a | 163 | # make the URL absolute if necessary |
00dd8d82 | 164 | my $admin = $self->{gen}{admin}; |
6a8a205a TC |
165 | my $link = $admin ? 'admin' : 'link'; |
166 | my $url = $art->{$link}; | |
99b7cef0 | 167 | if ($self->{abs_urls}) { |
6a8a205a TC |
168 | $url = $cfg->entryErr('site', 'url') . $url |
169 | unless $url =~ /^\w+:/; | |
170 | } | |
a319d280 | 171 | $url = escape_html($url); |
6a8a205a TC |
172 | |
173 | unless ($title) { | |
174 | $title = escape_html($art->{title}); | |
175 | } | |
3fa9f5b4 TC |
176 | |
177 | $target = $target ? qq! target="$target"! : ''; | |
63e99d77 | 178 | my $title_attrib = escape_html($art->{title}); |
8f84f3f1 TC |
179 | my $class_text = ''; |
180 | if ($type) { | |
181 | my $class = $self->tag_class($type); | |
182 | if ($class) { | |
183 | $class_text = qq/ class="$class"/; | |
184 | } | |
185 | } | |
6a8a205a | 186 | |
8f84f3f1 | 187 | return qq!<a href="$url" title="$title_attrib"$target$class_text>$title</a>!; |
6a8a205a TC |
188 | } |
189 | ||
def1a923 TC |
190 | sub popimage { |
191 | my ($self, $args) = @_; | |
192 | ||
193 | my $image_id; | |
194 | my ($image1_name, $image2_name, $align, $style) = split /\|/, $args; | |
195 | ||
196 | my $style_tag = ''; | |
197 | if ($style =~ /^\d/) { | |
198 | $style_tag = qq! style="padding: $style"!; | |
199 | } | |
200 | elsif ($style =~ /^\w+$/) { | |
201 | $style_tag = qq! class="$style"!; | |
202 | } | |
203 | else { | |
204 | $style_tag = qq! style="$style"!; | |
205 | } | |
206 | ||
207 | # work out the content inside the link | |
208 | my $inside; | |
209 | my $images = $self->{images}; | |
210 | if ($image1_name =~ /^\w+$/) { | |
211 | my $image1; | |
212 | if ($image1_name =~ /^\d+$/) { | |
213 | if ($image1_name >= 1 && $image1_name <= @$images) { | |
214 | $image1 = $images->[$image1_name - 1]; | |
215 | } | |
216 | else { | |
217 | return ''; | |
218 | } | |
219 | } | |
220 | else { | |
221 | ($image1) = grep $_->{name} && lc $_->{name} eq lc $image1_name, | |
222 | @$images; | |
223 | } | |
224 | ||
225 | $inside = qq!<img src="/images/$image1->{image}" ! | |
226 | . qq!width="$image1->{width}" height="$image1->{height}"! | |
227 | . qq! alt="! . escape_html($image1->{alt}) | |
228 | .qq!" border="0"!; | |
229 | $inside .= qq! align="$align"! if $align && $align ne 'center'; | |
230 | $inside .= $style_tag; | |
231 | $image_id = 'popimage_' . $pop_nameid++; | |
232 | ||
233 | $inside .= qq! name="$image_id" />!; | |
234 | } | |
235 | else { | |
236 | $inside = $image1_name; | |
237 | $image_id = ''; | |
238 | } | |
239 | ||
240 | # resolve the second image | |
241 | my $image2; | |
242 | if ($image2_name =~ /^\d+$/) { | |
243 | if ($image2_name >= 1 and $image2_name < @$images) { | |
244 | $image2 = $images->[$image2_name - 1]; | |
245 | } | |
246 | else { | |
247 | return ''; | |
248 | } | |
249 | } | |
250 | elsif ($image2_name =~ /^\w+$/) { | |
251 | ($image2) = grep $_->{name} && lc $_->{name} eq lc $image2_name, | |
252 | @$images | |
253 | or return ''; | |
254 | } | |
255 | else { | |
256 | return "** Unknown image2 $image2_name **"; | |
257 | } | |
258 | ||
259 | my $href = '/cgi-bin/image.pl?id=' . $image2->{articleId} | |
260 | . '&imid=' . $image2->{id}; | |
261 | my $popup_url = "/images/" . $image2->{image}; | |
262 | my $javascript = | |
263 | "return bse_popup_image($image2->{articleId}, $image2->{id}, " | |
264 | . "$image2->{width}, $image2->{height}, '$image_id', '$popup_url')"; | |
265 | my $link_start = qq!<a href="$href" onclick="$javascript" target="bse_image">!; | |
266 | my $link_end = "</a>"; | |
267 | ||
268 | if ($image_id) { | |
269 | if ($align eq 'center') { | |
270 | $link_start = qq!<div align="center">! . $link_start; | |
271 | $link_end .= '</div>'; | |
272 | } | |
273 | } | |
274 | else { | |
275 | if ($align) { | |
276 | $link_start = qq!<div align="$align"$style_tag>! . $link_start; | |
277 | $link_end .= "</div>"; | |
278 | } | |
279 | elsif ($style_tag) { | |
280 | $link_start = "<div$style_tag>".$link_start; | |
281 | $link_end .= "</div>"; | |
282 | } | |
283 | } | |
284 | ||
285 | return $self->_fix_spanned($link_start, $link_end, $inside); | |
286 | } | |
287 | ||
c5286ebe TC |
288 | sub filelink { |
289 | my ($self, $fileid, $text) = @_; | |
290 | ||
291 | my ($file) = grep $_->{name} eq $fileid, @{$self->{files}} | |
292 | or return "** unknown file $fileid **"; | |
293 | ||
294 | my $title = defined $text ? $text : $file->{displayName}; | |
295 | if ($file->{forSale}) { | |
296 | return escape_html($title); | |
297 | } | |
298 | else { | |
299 | my $url = "/cgi-bin/user.pl?download_file=1&file=$file->{id}"; | |
300 | return qq!<a href="! . escape_html($url) . qq!">! . | |
301 | escape_html($title) . "</a>"; | |
302 | } | |
303 | } | |
304 | ||
daee3409 TC |
305 | sub replace { |
306 | my ($self, $rpart) = @_; | |
307 | ||
308 | $$rpart =~ s#gimage\[([^\]\[]+)\]# $self->gimage($1) #ige | |
309 | and return 1; | |
8f84f3f1 TC |
310 | $$rpart =~ s#popdoclink\[(\w+)\|([^\]\[]+)\]# $self->doclink($1, $2, "_blank", 'popdoclink') #ige |
311 | and return 1; | |
312 | $$rpart =~ s#popdoclink\[(\w+)\]# $self->doclink($1, undef, "_blank", 'popdoclink') #ige | |
313 | and return 1; | |
314 | $$rpart =~ s#doclink\[(\w+)\|([^\]\[]+)\]# $self->doclink($1, $2, undef, 'doclink') #ige | |
315 | and return 1; | |
316 | $$rpart =~ s#doclink\[(\w+)\]# $self->doclink($1, undef, undef, 'doclink') #ige | |
317 | and return 1; | |
318 | ||
319 | $$rpart =~ s#popformlink\[(\w+)\|([^\]\[]+)\]# | |
320 | $self->formlink($1, 'popformlink', $2, '_blank') #ige | |
3fa9f5b4 | 321 | and return 1; |
8f84f3f1 TC |
322 | $$rpart =~ s#popformlink\[(\w+)\]# |
323 | $self->formlink($1, 'popformlink', undef, '_blank') #ige | |
3fa9f5b4 | 324 | and return 1; |
8f84f3f1 TC |
325 | $$rpart =~ s#formlink\[(\w+)\|([^\]\[]+)\]# |
326 | $self->formlink($1, 'formlink', $2) #ige | |
6a8a205a | 327 | and return 1; |
8f84f3f1 | 328 | $$rpart =~ s#formlink\[(\w+)\]# $self->formlink($1, 'formlink', undef) #ige |
6a8a205a | 329 | and return 1; |
c5286ebe TC |
330 | $$rpart =~ s#filelink\[\s*(\w+)\s*\|([^\]\[]+)\]# $self->filelink($1, $2) #ige |
331 | and return 1; | |
332 | $$rpart =~ s#filelink\[\s*(\w+)\s*\]# $self->filelink($1) #ige | |
333 | and return 1; | |
def1a923 TC |
334 | $$rpart =~ s#popimage\[([^\[\]]+)\]# $self->popimage($1) #ige |
335 | and return 1; | |
daee3409 TC |
336 | |
337 | return $self->SUPER::replace($rpart); | |
338 | } | |
339 | ||
8f84f3f1 TC |
340 | sub formlink { |
341 | my ($self, $id, $type, $text, $target) = @_; | |
342 | ||
343 | my $title = escape_html($self->{gen}{cfg}->entry("$id form", 'title', "Send us a comment")); | |
344 | $text ||= $title; | |
345 | ||
346 | my $extras = ''; | |
347 | if ($type) { | |
348 | my $class = $self->tag_class($type); | |
349 | if ($class) { | |
350 | $extras .= qq/ class="$class"/; | |
351 | } | |
352 | } | |
353 | if ($target) { | |
354 | $extras .= qq/ target="$target"/; | |
355 | } | |
356 | ||
357 | return qq!<a href="/cgi-bin/fmail.pl?form=$id" title="$title"$extras>$text</a>!; | |
358 | } | |
359 | ||
00dd8d82 TC |
360 | sub remove_doclink { |
361 | my ($self, $id) = @_; | |
362 | ||
363 | my $error; | |
364 | my $art = $self->_get_article ($id, \$error) | |
365 | or return $error; | |
366 | ||
367 | return $art->{title}; | |
368 | } | |
369 | ||
8f84f3f1 TC |
370 | sub remove_formlink { |
371 | my ($self, $id) = @_; | |
372 | ||
373 | return $self->{gen}{cfg}->entry("$id form", 'title', "Send us a comment"); | |
374 | } | |
375 | ||
def1a923 TC |
376 | sub remove_popimage { |
377 | my ($self, $args) = @_; | |
378 | ||
379 | my ($image1, $image2, $align, $style) = split /\|/, $args; | |
380 | ||
381 | my $images = $self->{images}; | |
382 | if ($image1 =~ /^\d+$/) { # image index | |
383 | if ($image1 >= 1 and $image1 <= @$images) { | |
384 | return $images->[$image1-1]{alt}; | |
385 | } | |
386 | } | |
387 | elsif ($image1 =~ /^\w+$/) { # image name | |
388 | my ($image) = grep $_->{name} eq $image1, @$images; | |
389 | return $image ? $image->{alt} : ''; | |
390 | } | |
391 | else { | |
392 | return $image1; | |
393 | } | |
394 | } | |
395 | ||
c5286ebe TC |
396 | sub remove_filelink { |
397 | my ($self, $fileid, $text) = @_; | |
398 | ||
399 | my ($file) = grep $_->{name} eq $fileid, @{$self->{files}} | |
400 | or return "** unknown file $fileid **"; | |
401 | ||
402 | return defined $text ? $text : $file->{displayName}; | |
403 | } | |
404 | ||
00dd8d82 TC |
405 | sub remove { |
406 | my ($self, $rpart) = @_; | |
407 | ||
408 | $$rpart =~ s#gimage\[([^\]\[]+)\]##ig | |
409 | and return 1; | |
829c9ed9 | 410 | $$rpart =~ s#popdoclink\[(\w+)\|([^\]\[]*)\]#$2#ig |
3fa9f5b4 TC |
411 | and return 1; |
412 | $$rpart =~ s#popdoclink\[(\w+)\]# $self->remove_doclink($1) #ige | |
413 | and return 1; | |
829c9ed9 | 414 | $$rpart =~ s#doclink\[(\w+)\|([^\]\[]*)\]#$2#ig |
00dd8d82 TC |
415 | and return 1; |
416 | $$rpart =~ s#doclink\[(\w+)\]# $self->remove_doclink($1) #ige | |
417 | and return 1; | |
8f84f3f1 TC |
418 | |
419 | $$rpart =~ s#popformlink\[(\w+)\|([^\]\[]*)\]#$2#ig | |
420 | and return 1; | |
421 | $$rpart =~ s#popformlink\[(\w+)\]# $self->remove_formlink($1) #ige | |
422 | and return 1; | |
c5286ebe TC |
423 | |
424 | $$rpart =~ s#filelink\[\s*(\w+)\s*\|([^\]\[]+)\]# $self->remove_filelink($1, $2) #ige | |
425 | and return 1; | |
426 | $$rpart =~ s#filelink\[\s*(\w+)\s*\]# $self->remove_filelink($1) #ige | |
427 | and return 1; | |
428 | ||
8f84f3f1 TC |
429 | $$rpart =~ s#formlink\[(\w+)\|([^\]\[]*)\]#$2#ig |
430 | and return 1; | |
def1a923 TC |
431 | $$rpart =~ s#formlink\[(\w+)\]# $self->remove_formlink($1) #ige |
432 | and return 1; | |
433 | $$rpart =~ s#popimage\[([^\[\]]+)\]# $self->remove_popimage($1) #ige | |
8f84f3f1 | 434 | and return 1; |
00dd8d82 TC |
435 | |
436 | } | |
437 | ||
8f84f3f1 TC |
438 | sub tag_class { |
439 | my ($self, $type) = @_; | |
440 | ||
441 | my $default = $type eq 'p' ? '' : $type; | |
442 | ||
443 | return $self->{gen}{cfg}->entry('body class', $type, $default); | |
444 | } | |
445 | ||
4772671f | 446 | 1; |