1 package BSE::Formatter;
5 use Digest::MD5 qw(md5_hex);
7 use base 'DevHelp::Formatter';
9 my $pop_nameid = 'AAAAAA';
23 my $self = $class->SUPER::new;
25 $self->{gen} = $opts{gen};
26 $self->{acts} = $opts{acts};
27 $self->{articles} = $opts{articles};
28 $self->{abs_urls} = $opts{abs_urls};
30 $self->{auto_images} = $opts{auto_images} || \$dummy;
31 $self->{images} = $opts{images};
32 $self->{files} = $opts{files};
33 $self->{templater} = $opts{templater};
35 my $cfg = $self->{gen}->{cfg};
36 if ($cfg->entry('html', 'mbcs', 0)) {
37 $self->{conservative_escape} = 1;
39 elsif ($cfg->entry('html', 'msentify', 0)) {
40 $self->{msentify} = 1;
43 $self->{redirect_links} = $cfg->entry('html', 'redirect_links', '');
44 $self->{redirect_salt} = $cfg->entry('html', 'redirect_salt', '');
50 my ($self, $im, $align, $url, $style) = @_;
52 my $text = qq!<img src="/images/$im->{image}" width="$im->{width}"!
53 . qq! height="$im->{height}" alt="! . escape_html($im->{alt}).'"'
55 $text .= qq! align="$align"! if $align && $align ne 'center';
57 if ($style =~ /^\d/) {
58 $text .= qq! style="padding: $style"!;
60 elsif ($style =~ /^\w+$/) {
61 $text .= qq! class="$style"!;
64 $text .= qq! style="$style"!;
68 $text = qq!<div align="center">$text</div>!
69 if $align && $align eq 'center';
70 # the text in $url would have been HTML escaped already, the url
71 # in the image record hasn't been
72 if (!$url && $im->{url}) {
73 $url = escape_html($im->{url});
76 $text = qq!<a href="$url">$text</a>!;
83 my ($self, $args) = @_;
85 my ($name, $align, $url, $style) = split /\|/, $args, 4;
86 my $im = $self->{gen}->get_gimage($name);
88 $self->_image($im, $align, $url);
96 my ($self, $args) = @_;
98 my $images = $self->{images};
99 my ($index, $align, $url, $style) = split /\|/, $args, 4;
102 if ($index =~ /^\d+$/) {
103 if ($index >=1 && $index <= @$images) {
104 $im = $images->[$index-1];
105 ${$self->{auto_images}} = 0;
108 elsif ($index =~ /^[a-z]\w*$/i){
110 for my $image (@$images) {
111 if ($image->{name} && lc $image->{name} eq lc $index) {
118 return $self->_image($im, $align, $url, $style);
126 my ($self, $name, $templateid, $maxdepth) = @_;
128 $self->{gen}->_embed_low($self->{acts}, $self->{articles}, $name,
129 $templateid, $maxdepth, $self->{templater});
133 my ($self, $url, $text) = @_;
135 if ($self->{redirect_links} =~ /[^\W\d]/) {
136 my $noredir_types = join '|', map quotemeta, split /,/, $self->{redirect_links};
137 if ($url =~ /^($noredir_types):/) {
138 return $self->SUPER::link($url, $text);
141 elsif (!$self->{redirect_links} || $url =~ /^mailto:/ || $url =~ /^\#/) {
142 return $self->SUPER::link($url, $text);
145 # formatter converted & to & but we want them as & so they undergo
146 # uri conversion correctly
147 $url = unescape_html($url);
148 $text = unescape_html($text);
149 my $redir_hash = substr(md5_hex($url, $text, $self->{redirect_salt}), 0, 16);
151 my $new_url = '/cgi-bin/nuser.pl/redirect?url='
152 . escape_uri($url) . "&h=$redir_hash";
154 $new_url .= '&title=' . escape_uri($text);
157 return $self->SUPER::link($new_url, $text);
161 my ($self, $id, $error) = @_;
163 my $cfg = $self->{gen}->{cfg}
164 or confess "cfg not set in acts";
166 if ($id =~ /^\d+$/) {
170 # try to find it in the config
171 my $work = $cfg->entry('articles', $id);
173 $$error = "** No article name '".escape_html($id)."' in the [articles] section of bse.cfg **";
176 $dispid = "$id ($work)";
179 my $art = $self->{articles}->getByPkey($id);
181 $$error = "** Cannot find article id $dispid **";
189 my ($self, $id, $title, $target, $type) = @_;
192 my $art = $self->_get_article($id, \$error)
195 my $cfg = $self->{gen}->{cfg}
196 or confess "cfg not set in acts";
198 # make the URL absolute if necessary
199 my $admin = $self->{gen}{admin};
200 my $link = $admin ? 'admin' : 'link';
201 my $url = $art->{$link};
202 if ($self->{abs_urls}) {
203 $url = $cfg->entryErr('site', 'url') . $url
204 unless $url =~ /^\w+:/;
206 $url = escape_html($url);
209 $title = escape_html($art->{title});
212 $target = $target ? qq! target="$target"! : '';
213 my $title_attrib = escape_html($art->{title});
216 my $class = $self->tag_class($type);
218 $class_text = qq/ class="$class"/;
222 return qq!<a href="$url" title="$title_attrib"$target$class_text>$title</a>!;
226 my ($self, $args) = @_;
229 my ($image1_name, $image2_name, $align, $style) = split /\|/, $args;
232 if ($style =~ /^\d/) {
233 $style_tag = qq! style="padding: $style"!;
235 elsif ($style =~ /^\w+$/) {
236 $style_tag = qq! class="$style"!;
239 $style_tag = qq! style="$style"!;
242 # work out the content inside the link
244 my $images = $self->{images};
245 if ($image1_name =~ /^\w+$/) {
247 if ($image1_name =~ /^\d+$/) {
248 if ($image1_name >= 1 && $image1_name <= @$images) {
249 $image1 = $images->[$image1_name - 1];
256 ($image1) = grep $_->{name} && lc $_->{name} eq lc $image1_name,
260 $inside = qq!<img src="/images/$image1->{image}" !
261 . qq!width="$image1->{width}" height="$image1->{height}"!
262 . qq! alt="! . escape_html($image1->{alt})
264 $inside .= qq! align="$align"! if $align && $align ne 'center';
265 $inside .= $style_tag;
266 $image_id = 'popimage_' . $pop_nameid++;
268 $inside .= qq! name="$image_id" />!;
271 $inside = $image1_name;
275 # resolve the second image
277 if ($image2_name =~ /^\d+$/) {
278 if ($image2_name >= 1 and $image2_name < @$images) {
279 $image2 = $images->[$image2_name - 1];
285 elsif ($image2_name =~ /^\w+$/) {
286 ($image2) = grep $_->{name} && lc $_->{name} eq lc $image2_name,
291 return "** Unknown image2 $image2_name **";
294 my $href = '/cgi-bin/image.pl?id=' . $image2->{articleId}
295 . '&imid=' . $image2->{id};
296 my $popup_url = "/images/" . $image2->{image};
298 "return bse_popup_image($image2->{articleId}, $image2->{id}, "
299 . "$image2->{width}, $image2->{height}, '$image_id', '$popup_url')";
300 my $link_start = qq!<a href="$href" onclick="$javascript" target="bse_image">!;
301 my $link_end = "</a>";
304 if ($align eq 'center') {
305 $link_start = qq!<div align="center">! . $link_start;
306 $link_end .= '</div>';
311 $link_start = qq!<div align="$align"$style_tag>! . $link_start;
312 $link_end .= "</div>";
315 $link_start = "<div$style_tag>".$link_start;
316 $link_end .= "</div>";
320 return $self->_fix_spanned($link_start, $link_end, $inside);
324 my ($self, $fileid, $text) = @_;
326 my ($file) = grep $_->{name} eq $fileid, @{$self->{files}}
327 or return "** unknown file $fileid **";
329 my $title = defined $text ? $text : $file->{displayName};
330 if ($file->{forSale}) {
331 return escape_html($title);
334 my $url = "/cgi-bin/user.pl?download_file=1&file=$file->{id}";
335 return qq!<a href="! . escape_html($url) . qq!">! .
336 escape_html($title) . "</a>";
341 my ($self, $rpart) = @_;
343 $$rpart =~ s#gimage\[([^\]\[]+)\]# $self->gimage($1) #ige
345 $$rpart =~ s#popdoclink\[(\w+)\|([^\]\[]+)\]# $self->doclink($1, $2, "_blank", 'popdoclink') #ige
347 $$rpart =~ s#popdoclink\[(\w+)\]# $self->doclink($1, undef, "_blank", 'popdoclink') #ige
349 $$rpart =~ s#doclink\[(\w+)\|([^\]\[]+)\]# $self->doclink($1, $2, undef, 'doclink') #ige
351 $$rpart =~ s#doclink\[(\w+)\]# $self->doclink($1, undef, undef, 'doclink') #ige
354 $$rpart =~ s#popformlink\[(\w+)\|([^\]\[]+)\]#
355 $self->formlink($1, 'popformlink', $2, '_blank') #ige
357 $$rpart =~ s#popformlink\[(\w+)\]#
358 $self->formlink($1, 'popformlink', undef, '_blank') #ige
360 $$rpart =~ s#formlink\[(\w+)\|([^\]\[]+)\]#
361 $self->formlink($1, 'formlink', $2) #ige
363 $$rpart =~ s#formlink\[(\w+)\]# $self->formlink($1, 'formlink', undef) #ige
365 $$rpart =~ s#filelink\[\s*(\w+)\s*\|([^\]\[]+)\]# $self->filelink($1, $2) #ige
367 $$rpart =~ s#filelink\[\s*(\w+)\s*\]# $self->filelink($1) #ige
369 $$rpart =~ s#popimage\[([^\[\]]+)\]# $self->popimage($1) #ige
372 return $self->SUPER::replace($rpart);
376 my ($self, $id, $type, $text, $target) = @_;
378 my $cfg = $self->{gen}{cfg};
379 my $section = "$id form";
380 my $title = escape_html($cfg->entry($section, 'title', "Send us a comment"));
382 my $secure = $cfg->entry($section, 'secure', 0);
383 my $abs_url = $self->{abs_urls} || $secure;
387 $prefix = $cfg->entryVar('site', $secure ? 'secureurl' : 'url');
392 my $class = $self->tag_class($type);
394 $extras .= qq/ class="$class"/;
398 $extras .= qq/ target="$target"/;
401 return qq!<a href="$prefix/cgi-bin/fmail.pl?form=$id" title="$title"$extras>$text</a>!;
405 my ($self, $id) = @_;
408 my $art = $self->_get_article ($id, \$error)
411 return $art->{title};
414 sub remove_formlink {
415 my ($self, $id) = @_;
417 return $self->{gen}{cfg}->entry("$id form", 'title', "Send us a comment");
420 sub remove_popimage {
421 my ($self, $args) = @_;
423 my ($image1, $image2, $align, $style) = split /\|/, $args;
425 my $images = $self->{images};
426 if ($image1 =~ /^\d+$/) { # image index
427 if ($image1 >= 1 and $image1 <= @$images) {
428 return $images->[$image1-1]{alt};
431 elsif ($image1 =~ /^\w+$/) { # image name
432 my ($image) = grep $_->{name} eq $image1, @$images;
433 return $image ? $image->{alt} : '';
440 sub remove_filelink {
441 my ($self, $fileid, $text) = @_;
443 my ($file) = grep $_->{name} eq $fileid, @{$self->{files}}
444 or return "** unknown file $fileid **";
446 return defined $text ? $text : $file->{displayName};
450 my ($self, $rpart) = @_;
452 $$rpart =~ s#gimage\[([^\]\[]+)\]##ig
454 $$rpart =~ s#popdoclink\[(\w+)\|([^\]\[]*)\]#$2#ig
456 $$rpart =~ s#popdoclink\[(\w+)\]# $self->remove_doclink($1) #ige
458 $$rpart =~ s#doclink\[(\w+)\|([^\]\[]*)\]#$2#ig
460 $$rpart =~ s#doclink\[(\w+)\]# $self->remove_doclink($1) #ige
463 $$rpart =~ s#popformlink\[(\w+)\|([^\]\[]*)\]#$2#ig
465 $$rpart =~ s#popformlink\[(\w+)\]# $self->remove_formlink($1) #ige
468 $$rpart =~ s#filelink\[\s*(\w+)\s*\|([^\]\[]+)\]# $self->remove_filelink($1, $2) #ige
470 $$rpart =~ s#filelink\[\s*(\w+)\s*\]# $self->remove_filelink($1) #ige
473 $$rpart =~ s#formlink\[(\w+)\|([^\]\[]*)\]#$2#ig
475 $$rpart =~ s#formlink\[(\w+)\]# $self->remove_formlink($1) #ige
477 $$rpart =~ s#popimage\[([^\[\]]+)\]# $self->remove_popimage($1) #ige
483 my ($self, $type) = @_;
485 my $default = $type eq 'p' ? '' : $type;
487 return $self->{gen}{cfg}->entry('body class', $type, $default);