$&, $' und $` grösstenteils entfernt.
[kivitendo-erp.git] / SL / Template / LaTeX.pm
index 291eb9f..31cb28f 100644 (file)
@@ -9,9 +9,93 @@ use Cwd;
 use English qw(-no_match_vars);
 use File::Basename;
 use File::Temp;
+use HTML::Entities ();
 use List::MoreUtils qw(any);
 use Unicode::Normalize qw();
 
+use SL::DB::Default;
+
+my %text_markup_replace = (
+  b => 'textbf',
+  i => 'textit',
+  u => 'underline',
+);
+
+sub _format_text {
+  my ($self, $content, %params) = @_;
+
+  $content = $::locale->quote_special_chars('Template/LaTeX', $content);
+
+  # Allow some HTML markup to be converted into the output format's
+  # corresponding markup code, e.g. bold or italic.
+  foreach my $key (keys(%text_markup_replace)) {
+    my $new   =  $text_markup_replace{$key};
+    $content =~ s/\$\<\$${key}\$\>\$(.*?)\$<\$\/${key}\$>\$/\\${new}\{$1\}/gi;
+  }
+
+  $content =~ s/[\x00-\x1f]//g;
+
+  return $content;
+}
+
+my %html_replace = (
+  '</p>'      => "\n\n",
+  '<ul>'      => "\\begin{itemize} ",
+  '</ul>'     => "\\end{itemize} ",
+  '<ol>'      => "\\begin{enumerate} ",
+  '</ol>'     => "\\end{enumerate} ",
+  '<li>'      => "\\item ",
+  '</li>'     => " ",
+  '<b>'       => "\\textbf{",
+  '</b>'      => "}",
+  '<strong>'  => "\\textbf{",
+  '</strong>' => "}",
+  '<i>'       => "\\textit{",
+  '</i>'      => "}",
+  '<em>'      => "\\textit{",
+  '</em>'     => "}",
+  '<u>'       => "\\underline{",
+  '</u>'      => "}",
+  '<s>'       => "\\sout{",
+  '</s>'      => "}",
+  '<sub>'     => "\\textsubscript{",
+  '</sub>'    => "}",
+  '<sup>'     => "\\textsuperscript{",
+  '</sup>'    => "}",
+  '<br/>'     => "\\newline ",
+  '<br>'      => "\\newline ",
+);
+
+sub _format_html {
+  my ($self, $content, %params) = @_;
+
+  $content =~ s{ \r+ }{}gx;
+  $content =~ s{ \n+ }{ }gx;
+  $content =~ s{ (?:\&nbsp;|\s)+ }{ }gx;
+  $content =~ s{ (?:\&nbsp;|\s)+$ }{}gx;
+  $content =~ s{ (?: <br/?> )+$ }{}gx;
+
+  my @parts = grep { $_ } map {
+    if (substr($_, 0, 1) eq '<') {
+      s{ +}{}g;
+      $html_replace{$_} || '';
+
+    } else {
+      $::locale->quote_special_chars('Template/LaTeX', HTML::Entities::decode_entities($_));
+    }
+  } split(m{(<.*?>)}x, $content);
+
+  $content =  join '', @parts;
+  $content =~ s{ (?: [\n\s] | \\newline )+$ }{}gx;
+
+  return $content;
+}
+
+my %formatters = (
+  html => \&_format_html,
+  text => \&_format_text,
+);
+
 sub new {
   my $type = shift;
 
@@ -21,24 +105,14 @@ sub new {
 }
 
 sub format_string {
-  my ($self, $variable) = @_;
-
-  $variable = $main::locale->quote_special_chars('Template/LaTeX', $variable);
-
-  # Allow some HTML markup to be converted into the output format's
-  # corresponding markup code, e.g. bold or italic.
-  my %markup_replace = ('b' => 'textbf',
-                        'i' => 'textit',
-                        'u' => 'underline');
-
-  foreach my $key (keys(%markup_replace)) {
-    my $new = $markup_replace{$key};
-    $variable =~ s/\$\<\$${key}\$\>\$(.*?)\$<\$\/${key}\$>\$/\\${new}\{$1\}/gi;
-  }
+  my ($self, $content, $variable) = @_;
 
-  $variable =~ s/[\x00-\x1f]//g;
+  my $formatter =
+       $formatters{ $self->{variable_content_types}->{$variable} }
+    // $formatters{ $self->{default_content_type} }
+    // $formatters{ text };
 
-  return $variable;
+  return $formatter->($self, $content, variable => $variable);
 }
 
 sub parse_foreach {
@@ -195,15 +269,15 @@ sub parse_block {
       $new_contents .= $self->substitute_vars(substr($contents, 0, $pos_foreach), @indices);
       substr($contents, 0, $pos_foreach) = "";
 
-      if ($contents !~ m|^$self->{tag_start_qm}foreach (.+?)$self->{tag_end_qm}|) {
+      if ($contents !~ m|^($self->{tag_start_qm}foreach (.+?)$self->{tag_end_qm})|) {
         $self->{"error"} = "Malformed $self->{tag_start}foreach$self->{tag_end}.";
         $main::lxdebug->leave_sub();
         return undef;
       }
 
-      my $var = $1;
+      my $var = $2;
 
-      substr($contents, 0, length($&)) = "";
+      substr($contents, 0, length($1)) = "";
 
       my $block;
       ($block, $contents) = $self->find_end($contents);
@@ -320,7 +394,7 @@ sub _force_mandatory_packages {
                       : defined($last_usepackage_line) ? $last_usepackage_line
                       :                                  scalar @{ $lines } - 1;
 
-  foreach my $package (qw(textcomp)) {
+  foreach my $package (qw(textcomp ulem)) {
     next if $used_packages{$package};
     splice @{ $lines }, $insertion_point, 0, "\\usepackage{${package}}\n";
     $insertion_point++;
@@ -336,7 +410,7 @@ sub parse {
     $self->{"error"} = "$form->{templates}/$form->{IN}: $!";
     return 0;
   }
-  binmode IN, ":utf8" if $::locale->is_utf8;
+  binmode IN, ":utf8";
   my @lines = <IN>;
   close(IN);
 
@@ -346,13 +420,13 @@ sub parse {
   my $contents = join("", @lines);
 
   # detect pagebreak block and its parameters
-  if ($contents =~ /$self->{tag_start_qm}pagebreak\s+(\d+)\s+(\d+)\s+(\d+)\s*$self->{tag_end_qm}(.*?)$self->{tag_start_qm}end(\s*pagebreak)?$self->{tag_end_qm}/s) {
-    $self->{"chars_per_line"} = $1;
-    $self->{"lines_on_first_page"} = $2;
-    $self->{"lines_on_second_page"} = $3;
-    $self->{"pagebreak_block"} = $4;
+  if ($contents =~ /^(.*)($self->{tag_start_qm}pagebreak\s+(\d+)\s+(\d+)\s+(\d+)\s*$self->{tag_end_qm}(.*?)$self->{tag_start_qm}end(\s*pagebreak)?$self->{tag_end_qm})/s) {
+    $self->{"chars_per_line"} = $3;
+    $self->{"lines_on_first_page"} = $4;
+    $self->{"lines_on_second_page"} = $5;
+    $self->{"pagebreak_block"} = $6;
 
-    substr($contents, length($`), length($&)) = "";
+    substr($contents, length($1), length($2)) = "";
   }
 
   $self->{"forced_pagebreaks"} = [];
@@ -372,13 +446,8 @@ sub parse {
     return 0;
   }
 
-  if ($::locale->is_utf8) {
-    binmode OUT, ":utf8";
-    print OUT Unicode::Normalize::normalize('C', $new_contents);
-
-  } else {
-    print OUT $new_contents;
-  }
+  binmode OUT, ":utf8";
+  print OUT Unicode::Normalize::normalize('C', $new_contents);
 
   if ($form->{"format"} =~ /postscript/i) {
     return $self->convert_to_postscript();
@@ -516,7 +585,7 @@ sub parse_and_create_pdf {
   $local_form->{IN}        = $template_file_name;
   $local_form->{tmpdir}    = $::lx_office_conf{paths}->{userspath};
   $local_form->{tmpfile}   = $tex_file_name;
-  $local_form->{templates} = $::myconfig{templates};
+  $local_form->{templates} = SL::DB::Default->get->templates;
 
   foreach (keys %params) {
     croak "The parameter '$_' must not be used." if exists $local_form->{$_};
@@ -525,7 +594,7 @@ sub parse_and_create_pdf {
 
   my $error;
   eval {
-    my $template = SL::Template::LaTeX->new($template_file_name, $local_form, \%::myconfig, $::lx_office_conf{paths}->{userspath});
+    my $template = SL::Template::LaTeX->new(file_name => $template_file_name, form => $local_form);
     my $result   = $template->parse($tex_fh) && $template->convert_to_pdf;
 
     die $template->{error} unless $result;