--- loncom/xml/londefdef.pm 2005/07/07 10:09:50 1.277 +++ loncom/xml/londefdef.pm 2006/03/23 22:34:53 1.323 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Tags Default Definition Module # -# $Id: londefdef.pm,v 1.277 2005/07/07 10:09:50 foxr Exp $ +# $Id: londefdef.pm,v 1.323 2006/03/23 22:34:53 foxr Exp $ # # # Copyright Michigan State University Board of Trustees @@ -47,7 +47,8 @@ use Image::Magick; use Apache::lonmenu(); use Apache::lonmeta(); use Apache::Constants qw(:common); - +use File::Basename; +# use Data::Dumper; BEGIN { @@ -55,6 +56,20 @@ BEGIN { } +# +# Dumps all elements of the table structure. +# Need this 'cause evidently when given an array, Data::Dumper only seems +# to dump element 0. +# +#sub debug_dump_table { +# my $lastrow = $#Apache::londefdef::table; +# &Apache::lonnet::logthis("Dumping table: Last row index: $lastrow"); +# my $row; +# for ($row =0; $row <= $lastrow; $row++ ) { +# my $text = Dumper($Apache::londefdef::table[$row]); +# &Apache::lonnet::logthis("table [ $row ]".$text); +# } +#} sub initialize_londefdef { $Apache::londefdef::TD_redirection=0; @Apache::londefdef::table = (); @@ -90,11 +105,21 @@ sub start_m { $inside=&Apache::run::evaluate($inside,$safeeval,$$parstack[-1]); #&Apache::lonxml::debug("M is evaulated to:$inside:"); } + my $tex = $inside; my $display=&Apache::lonxml::get_param('display',$parstack,$safeeval); $currentstring = &Apache::lontexconvert::converted(\$inside,$display); if ($Apache::lontexconvert::errorstring) { - &Apache::lonxml::warning("tth error: ". - $Apache::lontexconvert::errorstring); + my $errormsg='
'.&HTML::Entities::encode($Apache::lontexconvert::errorstring,'<>&"').'
occured while attempting to convert this TeX:
';
+	    $tex = &HTML::Entities::encode($tex,'<>&"');
+	    my ($linenumber) =
+		($Apache::lontexconvert::errorstring =~ /Line (\d+)/);
+	    if (defined($linenumber)) {
+		my @tex=split("\n",$tex);
+		$tex[$linenumber]=''.
+		    $tex[$linenumber].'';
+		$tex=join("\n",@tex);
+	    }
+	    &Apache::lonxml::warning($errormsg.$tex.'
'); $Apache::lontexconvert::errorstring=''; } #&Apache::lonxml::debug("M is ends with:$currentstring:"); @@ -109,8 +134,8 @@ sub start_m { # detect simple math mode entry exits, and convert them # to use \ensuremath if ($currentstring=~/^\s*\$[^\$].*[^\$]\$\s*$/) { - $currentstring=~s/^\$//; - $currentstring=~s/\$$//; + $currentstring=~s/^(\s*)\$/$1/; + $currentstring=~s/\$(\s*)$/$1/; $currentstring='\ensuremath{'.$currentstring.'}'; } $Apache::lonxml::post_evaluate=0; @@ -128,10 +153,11 @@ sub end_m { } sub start_tthoption { - my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_; + my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style) = @_; my $result; if ($target eq 'web') { - my $inside = &Apache::lonxml::get_all_text("/tthoption",$parser); + my $inside = &Apache::lonxml::get_all_text("/tthoption",$parser, + $style); $inside=~s/^\s*//; if ($env{'browser.mathml'}) { &tth::ttmoptions($inside); @@ -157,15 +183,17 @@ sub start_html { if ($target eq 'web' || $target eq 'edit' || $target eq 'webgrade' ) { $currentstring = &Apache::lonxml::xmlbegin(); } elsif ($target eq 'tex') { - $currentstring .= '\documentclass[letterpaper]{article}'; + $currentstring .= '\documentclass[letterpaper,twoside]{article}'; if (($env{'form.latex_type'}=~'batchmode') || (!$env{'request.role.adv'})) {$currentstring .='\batchmode';} $currentstring .= '\newcommand{\keephidden}[1]{}'. '\renewcommand{\deg}{$^{\circ}$}'. + '\usepackage{multirow}'. '\usepackage{longtable}'. '\usepackage{textcomp}'. '\usepackage{makeidx}'. '\usepackage[dvips]{graphicx}'. + '\usepackage{wrapfig}'. '\usepackage{picins}'. '\usepackage{epsfig}'. '\usepackage{calc}'. @@ -367,13 +395,13 @@ sub end_title { #-- tag (end tag forbidden) sub start_meta { - my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_; + my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style) = @_; my $currentstring = ''; if ($target eq 'web') { my $args=''; if ( $#$parstack > -1 ) { $args=$$parstack[$#$parstack]; } if ($args eq '') { - &Apache::lonxml::get_all_text("/meta",$parser); + &Apache::lonxml::get_all_text("/meta",$parser,$style); } else { $currentstring = $token->[4]; } @@ -436,7 +464,7 @@ sub end_meta { # accessrule sub start_accessrule { - my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_; + my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style) = @_; my $currentstring = ''; my $eff=&Apache::lonxml::get_param ('effect',$parstack,$safeeval,undef,1); @@ -455,7 +483,7 @@ sub start_accessrule { my $args=''; if ( $#$parstack > -1 ) { $args=$$parstack[$#$parstack]; } if ($args eq '') { - &Apache::lonxml::get_all_text("/accessrule",$parser); + &Apache::lonxml::get_all_text("/accessrule",$parser,$style); } else { $currentstring = $token->[4]; } @@ -535,23 +563,25 @@ sub start_body { $token->[2]->{'onunload'}=&Apache::lonmenu::unloadevents(). ';'.$onUnload; - if ($env{'request.state'} ne 'construct') { - $currentstring .= '<'.$token->[1]; - } + $currentstring .= '<'.$token->[1]; foreach (keys %{$token->[2]}) { $currentstring.=' '.$_.'="'.$token->[2]->{$_}.'"'; } - if ($env{'request.state'} ne 'construct') { - $currentstring.='>'; + $currentstring.='>'; + &Apache::lontexconvert::jsMath_reset(); + if ($env{'environment.texengine'} eq 'jsMath') { + $currentstring.=&Apache::lontexconvert::jsMath_header(); } if ($env{'request.state'} ne 'published') { - my $remote=($env{'environment.remote'} ne 'off'); - $currentstring=&Apache::loncommon::bodytag(undef,undef, - $currentstring,$remote); + if ($env{'environment.remote'} eq 'off') { + $currentstring.= + &Apache::lonmenu::constspaceform(). + &Apache::lonmenu::menubuttons(1,'web',1); + } $currentstring.=(< - - +
+ +
EDITBUTTON } else { $currentstring.=&Apache::lonmenu::menubuttons(undef,$target,1); @@ -565,7 +595,7 @@ EDITBUTTON sub end_body { my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_; - my $currentstring = &end_p; # Close off unclosed

+ my $currentstring = &end_p(); # Close off unclosed

if ($target eq 'web') { $currentstring .= &Apache::lonxml::xmlend($target,$parser); } elsif ($target eq 'tex') { @@ -574,20 +604,26 @@ sub end_body { return $currentstring; } +# \begin{center} causes a new paragprah spacing that looks odd inside +# of a table cell +sub center_correction { return '\vspace*{-6 mm}'; } #--

tag (end tag required) sub start_center { - my ($target,$token) = @_; - my $currentstring = &end_p; # Close off any prior para. + my ($target,$token,$tagstack) = @_; + my $currentstring = &end_p(); # Close off any prior para. if ($target eq 'web') { $currentstring .= $token->[4]; } elsif ($target eq 'tex') { + if (&is_inside_of($tagstack, "table")) { + $currentstring .= ¢er_correction(); + } $currentstring .= '\begin{center}'; } return $currentstring; } sub end_center { - my ($target,$token) = @_; + my ($target,$token,$tagstack) = @_; my $currentstring = ''; if ($target eq 'web') { $currentstring = $token->[2]; @@ -598,13 +634,15 @@ sub end_center { } #-- tag (end tag required) +# NOTE: In TeX mode disables internal

sub start_b { my ($target,$token) = @_; my $currentstring = ''; if ($target eq 'web') { $currentstring = $token->[4]; } elsif ($target eq 'tex') { - $currentstring = '\textbf{'; + &disable_para(); + $currentstring .= '\textbf{'; } return $currentstring; } @@ -615,18 +653,21 @@ sub end_b { if ($target eq 'web') { $currentstring = $token->[2]; } elsif ($target eq 'tex') { - $currentstring = '}'; + &enable_para(); + $currentstring = '}'; } return $currentstring; } #-- tag (end tag required) +# NOTE: in TeX mode disables internal

sub start_strong { my ($target,$token) = @_; my $currentstring = ''; if ($target eq 'web') { $currentstring = $token->[4]; } elsif ($target eq 'tex') { + &disable_para(); $currentstring = '\textbf{'; } return $currentstring; @@ -638,6 +679,7 @@ sub end_strong { if ($target eq 'web') { $currentstring = $token->[2]; } elsif ($target eq 'tex') { + &enable_para(); $currentstring = '}'; } return $currentstring; @@ -646,7 +688,7 @@ sub end_strong { #--

tag (end tag required) sub start_h1 { my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_; - my $currentstring = &end_p; # Close off any prior para. + my $currentstring = &end_p(); # Close off any prior para. if ($target eq 'web') { $currentstring .= $token->[4]; } elsif ($target eq 'tex') { @@ -695,7 +737,7 @@ sub end_h1 { #--

tag sub start_h2 { my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_; - my $currentstring = &end_p; # Close off any prior para. + my $currentstring = &end_p(); # Close off any prior para. if ($target eq 'web') { $currentstring .= $token->[4]; } elsif ($target eq 'tex') { @@ -738,7 +780,7 @@ sub end_h2 { #--

tag sub start_h3 { my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_; - my $currentstring = &end_p; # Close off any prior para. + my $currentstring = &end_p(); # Close off any prior para. if ($target eq 'web') { $currentstring .= $token->[4]; } elsif ($target eq 'tex') { @@ -781,7 +823,7 @@ sub end_h3 { #--

tag sub start_h4 { my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_; - my $currentstring = &end_p; # Close off any prior para. + my $currentstring = &end_p(); # Close off any prior para. if ($target eq 'web') { $currentstring .= $token->[4]; } elsif ($target eq 'tex') { @@ -824,7 +866,7 @@ sub end_h4 { #--

tag sub start_h5 { my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_; - my $currentstring = &end_p; # Close off any prior paras. + my $currentstring = &end_p(); # Close off any prior paras. if ($target eq 'web') { $currentstring .= $token->[4]; } elsif ($target eq 'tex') { @@ -867,7 +909,7 @@ sub end_h5 { #--
tag sub start_h6 { my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_; - my $currentstring = &end_p; # Close off any prior paras. + my $currentstring = &end_p(); # Close off any prior paras. if ($target eq 'web') { $currentstring .= $token->[4]; } elsif ($target eq 'tex') { @@ -1125,39 +1167,58 @@ sub end_q { my $closing_string = ''; # String required to close

+# Some tags are

fragile meaning that

inside of them +# does not work within TeX mode. This is managed via the +# counter below: +# + + my $para_disabled = 0; + +sub disable_para { + $para_disabled++; +} +sub enable_para { + $para_disabled--; +} + + #--

tag (end tag optional) #optional attribute - align="center|left|right" sub start_p { my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_; - my $currentstring = &end_p; # close off prior para if in progress. + my $currentstring = ''; if ($target eq 'web') { + $currentstring .= &end_p(); # close off prior para if in progress. $currentstring .= $token->[4]; - $closing_string = '

'; # Not sure this is correct. - } elsif ($target eq 'tex') { + if (! ($currentstring =~ /\//)) { + $closing_string = '

'; # Deal correctly with

e.g. + } + } elsif ($target eq 'tex' && !$para_disabled) { + + $currentstring .= &end_p(); # close off prior para if in progress. my $align=&Apache::lonxml::get_param('align',$parstack,$safeeval,undef,1); if ($align eq 'center') { $currentstring .='\begin{center}\par'; $closing_string = '\end{center}'; + if (&is_inside_of($tagstack, "table")) { + $currentstring = ¢er_correction().$currentstring; + } } elsif ($align eq 'right') { - $currentstring.='\makebox['.$env{'form.textwidth'}.']{\hfill\llap{'; - $closing_string= '}}'; + $currentstring.="\n".'{\flushright '; +# $currentstring.='\makebox['.$env{'form.textwidth'}.']{\hfill\llap{'; + $closing_string= "}\n"; } elsif ($align eq 'left') { - $currentstring.='\noindent\makebox['.$env{'form.textwidth'}.']{\rlap{'; - $closing_string = '}\hfill}'; + $currentstring.= "\n".'{\flushleft '; +# $currentstring.='\noindent\makebox['.$env{'form.textwidth'}.']{{'; + $closing_string = "}\n"; } else { $currentstring.='\par '; - $closing_string = '\strut\\\\\strut'; - } - my $signal=1;#

does not work inside ... - foreach my $tag (@$tagstack) { - if (lc($tag) eq 'b') { - $signal=0; + if (&is_inside_of($tagstack, 'table')) { + $closing_string = '\vskip 0pt'; # Seems to be consistent with

in tables. + } else { + $closing_string = '\strut\\\\\strut '; } - } - if (!$signal) { - $currentstring = &end_p; # Just close the prior? Not sure this is correct - $closing_string = ''; # Probably correct? - } + } } return $currentstring; @@ -1166,9 +1227,16 @@ sub start_p { # End paragraph processing just requires that we output the # closing string that was saved and blank it. sub end_p { - my $current_string = $closing_string; - $closing_string = ''; # Not in a para anymore. - return $current_string; + # Note only 'tex' mode uses disable_para and enable_para + # so we don't need to know the target in the check below: + + if (!$para_disabled) { + my $current_string = $closing_string; + $closing_string = ''; # Not in a para anymore. + return $current_string; + } else { + return ''; + } } } @@ -1181,6 +1249,9 @@ sub start_br { } elsif ($target eq 'tex') { my @tempo=@$tagstack; my $signal=0; + # Not going to factor this to is_inside_of since that would require + # multiple stack traversals. + # for (my $i=$#tempo;$i>=0;$i--) { if (($tempo[$i] eq 'b') || ($tempo[$i] eq 'strong') || ($tempo[$i] eq 'ol') || ($tempo[$i] eq 'ul') || @@ -1417,7 +1488,7 @@ sub end_sup { #--


tag (end tag forbidden) sub start_hr { my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_; - my $currentstring = &end_p; # End enclosing para. + my $currentstring = &end_p(); # End enclosing para. if ($target eq 'web') { $currentstring .= $token->[4]; } elsif ($target eq 'tex') { @@ -1455,12 +1526,47 @@ sub end_hr { } #--
tag (end tag required) +{ + +# Since div can be nested, the stack below is used +# in 'tex' mode to store the ending strings +# for the div stack. + + my @div_end_stack; + sub start_div { - my ($target,$token) = @_; - my $currentstring = &end_p; # Close enclosing para. + my ($target,$token, $tagstack, $parstack, $parser, $safeeval) = @_; + my $currentstring = &end_p(); # Close enclosing para. if ($target eq 'web') { $currentstring .= $token->[4]; } + if ($target eq 'tex') { + # 4 possible alignments: left, right, center, and -missing-. + + my $endstring = ''; + + my $align = lc(&Apache::lonxml::get_param('align', $parstack, + $safeeval, undef, 1)); + if ($align eq 'center') { + $currentstring .= '\begin{center}'; + $endstring = '\end{center}'; + if (&is_inside_of($tagstack, "table")) { + $currentstring = ¢er_correction().$currentstring; + } + } + elsif ($align eq 'right') { + $currentstring .= '\begin{flushright}'; + $endstring .= '\end{flushright}'; + } elsif ($align eq 'left') { + $currentstring .= '\begin{flushleft}'; + $endstring = '\end{flushleft}'; + } else { + + } + $currentstring .= "\n"; # For human readability. + $endstring = "\n$endstring\n"; # For human readability + push(@div_end_stack, $endstring); + } return $currentstring; } @@ -1469,9 +1575,14 @@ sub end_div { my $currentstring = ''; if ($target eq 'web') { $currentstring .= $token->[2]; - } + } + if ($target eq 'tex') { + my $endstring = pop @div_end_stack; + $currentstring .= $endstring; + } return $currentstring; } +} #-- tag (end tag required) sub start_a { @@ -1539,7 +1650,7 @@ sub start_li { sub end_li { my ($target,$token) = @_; - my $currentstring = &end_p; # In case there's a

in the

  • + my $currentstring = &end_p(); # In case there's a

    in the

  • if ($target eq 'web') { $currentstring .= $token->[2]; } @@ -1575,7 +1686,7 @@ sub end_u { #--
      tag (end tag required) sub start_ul { my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_; - my $currentstring = &end_p; # Close off enclosing list. + my $currentstring = &end_p(); # Close off enclosing list. if ($target eq 'web') { $currentstring .= $token->[4]; } elsif ($target eq 'tex') { @@ -1642,7 +1753,7 @@ sub end_menu { #-- tag (end tag required) sub start_dir { my ($target,$token) = @_; - my $currentstring = &end_p; # In case there's a

      prior to the list. + my $currentstring = &end_p(); # In case there's a

      prior to the list. if ($target eq 'web') { $currentstring .= $token->[4]; } elsif ($target eq 'tex') { @@ -1665,7 +1776,7 @@ sub end_dir { #--

        tag (end tag required) sub start_ol { my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_; - my $currentstring = &end_p; # In case there's a

        prior to the list. + my $currentstring = &end_p(); # In case there's a

        prior to the list. if ($target eq 'web') { $currentstring .= $token->[4]; } elsif ($target eq 'tex') { @@ -1719,7 +1830,7 @@ sub end_ol { #--

        tag (end tag required) sub start_dl { my ($target,$token) = @_; - my $currentstring = &end_p; # In case there's a

        unclosed prior to the list. + my $currentstring = &end_p(); # In case there's a

        unclosed prior to the list. if ($target eq 'web') { $currentstring .= $token->[4]; } elsif ($target eq 'tex') { @@ -1835,7 +1946,7 @@ sub end_dd { sub start_table { my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_; my $textwidth = ''; - my $currentstring = &end_p; + my $currentstring = &end_p(); if ($target eq 'web') { $currentstring .= $token->[4]; } elsif ($target eq 'tex') { @@ -1859,24 +1970,35 @@ sub start_table { } } } + + # width either comes forced from the TeXwidth or the width parameters. + # in either case it can be a percentage or absolute width. + # in the width case we ignore absolute width my $TeXwidth = &Apache::lonxml::get_param('TeXwidth',$parstack,$safeeval,undef,0); - if (not defined $TeXwidth) { - my $htmlwidth = &Apache::lonxml::get_param('width',$parstack,$safeeval,undef,1); - if ($htmlwidth=~/%/) { - $Apache::londefdef::table[-1]{'percent'}=1; - $htmlwidth=~/(\d+)/; - $Apache::londefdef::table[-1]{'width'}=$1*$textwidth/100;; - } else { - $Apache::londefdef::table[-1]{'width'}=$textwidth; + if (!defined($TeXwidth)) { + my $htmlwidth = &Apache::lonxml::get_param('width',$parstack, + $safeeval,undef,1); + if ($htmlwidth =~ /%/) { + $TeXwidth = $htmlwidth; + } else { + $TeXwidth = $textwidth; } - } elsif ($TeXwidth=~/%/) { + } else { + $Apache::londefdef::table[-1]{'forcedtablewidth'} = 1; + } + if ($TeXwidth=~/%/) { $Apache::londefdef::table[-1]{'percent'}=1; $TeXwidth=~/(\d+)/; $Apache::londefdef::table[-1]{'width'}=$1*$textwidth/100; } else { - $Apache::londefdef::table[-1]{'forcetablewidth'}=1; $Apache::londefdef::table[-1]{'width'}=$TeXwidth; - } + } + # In the end, however the table width cannot be wider than $textwidth... + + if ($Apache::londefdef::table[-1]{'width'} > $textwidth) { + $Apache::londefdef::table[-1]{'width'} = $textwidth; + } + #table's border my $border = &Apache::lonxml::get_param('border',$parstack,$safeeval); my $permission=&Apache::lonxml::get_param('TeXDropEmptyColumns',$parstack,$safeeval,undef,0); @@ -1891,7 +2013,9 @@ sub start_table { $Apache::londefdef::table[-1]{'vvinc'} = ''; } if ($#Apache::londefdef::table==0) { - $Apache::londefdef::table[-1]{'output'}='\strut\newline\strut\setlength{\tabcolsep}{1 mm}'; + # Note that \newline seems to destroy the alignment envs. + # $Apache::londefdef::table[-1]{'output'}='\strut\newline\strut\setlength{\tabcolsep}{1 mm}'; + $Apache::londefdef::table[-1]{'output'}='\strut'.'\\\\'."\n".'\strut\setlength{\tabcolsep}{1 mm}'; } $Apache::londefdef::table[-1]{'output'}.=' \noindent \begin{tabular} '; $Apache::londefdef::table[-1]{'TeXlen'}=[]; @@ -1902,7 +2026,9 @@ sub start_table { $Apache::londefdef::table[-1]{'content'}=[]; $Apache::londefdef::table[-1]{'align'}=[]; $currentstring.='\keephidden{NEW TABLE ENTRY}'; - } + + + } return $currentstring; } @@ -1916,6 +2042,7 @@ sub end_table { my $output = ''; my $WARNING=''; #width of columns from TeXwidth attributes + for (my $in=0;$in<=$Apache::londefdef::table[-1]{'row_number'};$in++) { for (my $jn=0;$jn<=$Apache::londefdef::table[-1]{'counter_columns'};$jn++) { if ($Apache::londefdef::table[-1]{'TeXlen'}[0][$jn]<$Apache::londefdef::table[-1]{'TeXlen'}[$in][$jn]) { @@ -2098,25 +2225,114 @@ sub end_table { $header_of_table .= '}'; #fill the table for (my $in=0;$in<=$Apache::londefdef::table[-1]{'row_number'};$in++) { + my $have_rowspan = 0; for (my $jn=0;$jn<=$#fwidth;$jn++) { + + #----------------------------------------------------------- + # I think this order of doing things will ensure that + # single rowspan, columspan and combined row/colspans will + # work correctly. LaTeX is delicate here. + # RF. + + # Start a rowspan if necessary: + + my $rowspan = $Apache::londefdef::table[-1]{'rowspan'}[$in][$jn]; + my $colspan = $Apache::londefdef::table[-1]{'colspan'}[$in][$jn]; + # + # Do the appropriate magic if this has a colspan + # + + if ($colspan > 1) { + $output .= '\multicolumn{'. + $colspan + .'}{|l|}{'; + } + + if ($rowspan > 1) { + $have_rowspan++; + $output .= '\multirow{'.$rowspan.'}[0]{'.$fwidth[$jn].'mm}{'; + } + if (($rowspan eq '^') || ($rowspan eq '_')) { + $have_rowspan++; + } + #-------------------------------------------------------------- + if ($Apache::londefdef::table[-1]{'align'}[$in][$jn] eq 'c') { - $output.='\vspace*{-6 mm}\begin{center}'; + $output.=¢er_correction().'\begin{center}'; } elsif ($Apache::londefdef::table[-1]{'align'}[$in][$jn] eq 'r') { $output.=' \hfill \llap{' } $output.=$Apache::londefdef::table[-1]{'content'}[$in][$jn]; if ($Apache::londefdef::table[-1]{'align'}[$in][$jn] eq 'c') { - $output.='\end{center}\vspace*{-6 mm}'; + $output.='\end{center}'; } elsif ($Apache::londefdef::table[-1]{'align'}[$in][$jn] eq 'r') { $output.='} '; } + # Close off any open multirow: + + if ($rowspan > 1) { + $output .= '}'; + } + # Close off the colspan... + # + if ($colspan > 1) { + $output .= '}'; + $jn += $colspan-1; # Adjust for number of rows really left. + } if ($jn!=$#fwidth) {$output.=' '.$Apache::londefdef::table[-1]{'vinc'};} } - $output.=' \\\\ '.$Apache::londefdef::table[-1]{'hinc'}.' '; + # If have_rowspan > 0, and borders are on, then + # we need to do more than put an \hline at the bottom of row. + # we need to do the appropriate \cline to ensure that + # the spanned rows don't have \hlines through them. + + if (($Apache::londefdef::table[-1]{'hinc'} =~ /\\hline/) && $have_rowspan) { + $output .= ' \\\\ '; + for (my $jn=0; $jn<=$#fwidth;$jn++) { + my $rowspan = $Apache::londefdef::table[-1]{'rowspan'}[$in][$jn]; + if ($rowspan ne "^") { + if (($rowspan <= 1) || ($rowspan eq '_')) { + my $column = $jn+1; + $output .= '\cline{'.$column.'-'.$column.'} '; + } + } + } + + } else { + $output.=' \\\\ '.$Apache::londefdef::table[-1]{'hinc'}.' '; + } } - $Apache::londefdef::table[-1]{'output'} .= $header_of_table.$Apache::londefdef::table[-1]{'hinc'}.$output.'\end{tabular}\strut\newline\strut '; + # Note that \newline destroys alignment env's produced by e.g.

        + # $Apache::londefdef::table[-1]{'output'} .= $header_of_table.$Apache::londefdef::table[-1]{'hinc'}.$output.'\end{tabular}\strut\newline\strut '; + $Apache::londefdef::table[-1]{'output'} .= $header_of_table.$Apache::londefdef::table[-1]{'hinc'}.$output.'\end{tabular}\strut'.'\\\\'."\n".'\strut '; if ($#Apache::londefdef::table > 0) { my $inmemory = $Apache::londefdef::table[-1]{'output'}; + # Figure out max/and min width by summing us and then + # apply that to the current column of the table we nest in + # if it's larger than the current width or the current width + # is undefined. + # + my $min_nested_width = 0; + my $max_nested_width = 0; + for (my $col = 0; $col <= $Apache::londefdef::table[-1]{'counter_columns'}; $col++) { + $min_nested_width += $min_len[$col]; + $max_nested_width += $max_len[$col]; + + } + # Fudge in an extra 5 mm for borders etc: + + $min_nested_width += 5; + $max_nested_width += 5; + + my $outer_column = $Apache::londefdef::table[-2]{'counter_columns'}; + my $outer_row = $Apache::londefdef::table[-2]{'row_number'}; + if ($min_nested_width > $Apache::londefdef::table[-2]{'minlen'}[$outer_row][$outer_column]) { + $Apache::londefdef::table[-2]{'minlen'}[$outer_row][$outer_column] = $min_nested_width; + } + if ($max_nested_width > $Apache::londefdef::table[-2]{'maxlen'}[$outer_row][$outer_column]) { + $Apache::londefdef::table[-2]{'maxlen'}[$outer_row][$outer_column] = $max_nested_width; + } + pop @Apache::londefdef::table; push @{$Apache::londefdef::table[-1]{'include'}}, $inmemory; } else { @@ -2143,6 +2359,10 @@ sub start_tr { push @ {$Apache::londefdef::table[-1]{'rows'} }, 'l'; } push ( @{ $Apache::londefdef::table[-1]{'rowdata'} }, $Apache::londefdef::table[-1]{'hinc'}); + # + # Need to save the number of table columns to preserve the max # columns. + # + $Apache::londefdef::table[-1]{'prior_columns'} = $Apache::londefdef::table[-1]{'counter_columns'}; $Apache::londefdef::table[-1]{'counter_columns'} = -1; push @ {$Apache::londefdef::table[-1]{'TeXlen'}}, []; push @ {$Apache::londefdef::table[-1]{'objectlen'}}, []; @@ -2155,13 +2375,21 @@ sub start_tr { sub end_tr { my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_; - my $currentstring = &end_p; # Close any pending

        in the row. + my $currentstring = &end_p(); # Close any pending

        in the row. if ($target eq 'web') { $currentstring .= $token->[2]; } elsif ($target eq 'tex') { if ($Apache::londefdef::TD_redirection) { &end_td_tex($parstack,$parser,$safeeval); } + # Counter columns must be the maximum number of columns seen + # in the table so far so: + if ($Apache::londefdef::table[-1]{'prior_columns'} > $Apache::londefdef::table[-1]{'counter_columns'}) { + $Apache::londefdef::table[-1]{'counter_columns'} = $Apache::londefdef::table[-1]{'prior_columns'}; + } + + + } return $currentstring; } @@ -2216,8 +2444,51 @@ sub start_td_tex { sub end_td_tex { my ($parstack,$parser,$safeeval) = @_; - my $current_row = $Apache::londefdef::table[-1]{'row_number'}; - my $data=&Apache::lonxml::endredirection(); + my $current_row = $Apache::londefdef::table[-1]{'row_number'}; + my $current_column = $Apache::londefdef::table[-1]{'counter_columns'}; + my $data = &Apache::lonxml::endredirection(); + + # The rowspan array of the table indicates which cells are part of a span. + # n indicates the start of a span set of n rows. + # ^ indicates a cell that continues a span set. + # _ indicates the cell is at the bottom of a span set. + # If this and subsequent cells are part of a rowspan, we must + # push along the row until we find one that is not. + + while ((defined $Apache::londefdef::table[-1]{'rowspan'}[$current_row] [$current_column]) + && ($Apache::londefdef::table[-1]{'rowspan'}[$current_row][$current_column] =~ /[\^\_]/)) { + # Part of a span. + push @ {$Apache::londefdef::table[-1]{'content'}[-1]}, ''; + $current_column++; + } + $Apache::londefdef::table[-1]{'counter_columns'} = $current_column; + + + # Get the column and row spans. + # Colspan can be done via \multicolumn if I can figure out the data structs. + + my $colspan = &Apache::lonxml::get_param('colspan', $parstack, $safeeval, undef, 0); + if (!$colspan) { + $colspan = 1; + } + + my $rowspan = &Apache::lonxml::get_param('rowspan', $parstack, $safeeval, undef, 0); + if (!$rowspan) { + $rowspan = 1; + } + + + + for (my $c = 0; $c < $colspan; $c++) { + $Apache::londefdef::table[-1]{'rowspan'}[$current_row][$current_column+$c] = $rowspan; + for (my $i = 1; $i < $rowspan; $i++) { + $Apache::londefdef::table[-1]{'rowspan'}[$current_row+$i][$current_column+$c] = '^'; + if ($i == ($rowspan-1)) { + $Apache::londefdef::table[-1]{'rowspan'}[$current_row+$i][$current_column+$c] = '_'; + } + } + } + my $TeXwidth=&Apache::lonxml::get_param('TeXwidth',$parstack,$safeeval,undef,0); if (defined $TeXwidth) { push @ {$Apache::londefdef::table[-1]{'objectlen'}[$Apache::londefdef::table[-1]{'row_number'}] },'0'; @@ -2294,11 +2565,43 @@ sub end_td_tex { push @ {$Apache::londefdef::table[-1]{'minlen'}[$Apache::londefdef::table[-1]{'row_number'}] },$min_length; } } - for (my $in=0; $in<=$#{$Apache::londefdef::table[-1]{'include'}};$in++) { - $data=~s/\\keephidden\{NEW TABLE ENTRY\}/$Apache::londefdef::table[-1]{'include'}[$in]/; - } + # Substitute all of the tables nested in this cell in their appropriate places. + + + my $nested_count = $#{$Apache::londefdef::table[-1]{'include'}}; # This one is constant... + for (my $in=0; $in<=$nested_count; $in++) { + my $nested = shift @{$Apache::londefdef::table[-1]{'include'}}; + $nested =~ s/\\end\{tabular\}\\strut\\\\/\\end\{tabular\}/; + # $data=~s/\\keephidden\{NEW TABLE ENTRY\}/$Apache::londefdef::table[-1]{'include'}[$in]/; + $data =~ s/\\keephidden\{NEW TABLE ENTRY\}/$nested/; + + } + # Should be be killing off the 'include' elements as they're used up? + push @ {$Apache::londefdef::table[-1]{'content'}[-1] },$data; - return''; + + + + + # the colspan array will indicate how many columns will be spanned by this + # cell..this requires that counter_columns also be adjusted accordingly + # so that the next bunch of text goes in the right cell. Note that since + # counter_columns is incremented in the start_td_tex, we adjust by colspan-1. + # + + $Apache::londefdef::table[-1]{'counter_columns'} += $colspan -1; + for (my $i = 0; $i < ($colspan -1); $i++) { + push @ {$Apache::londefdef::table[-1]{'content'}[-1] },''; + } + for (my $r = 0; $r < $rowspan; $r++) { + $Apache::londefdef::table[-1]{'colspan'}[$current_row+$r][$current_column] = $colspan; + # Put empty text in spanned cols. + + } + + + + return ''; } sub end_td { @@ -2432,7 +2735,7 @@ sub end_th_tex { sub end_th { my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_; - my $currentstring = &end_p; # Close any open

        in the row. + my $currentstring = &end_p(); # Close any open

        in the row. if ($target eq 'web') { $currentstring .= $token->[2]; } elsif ($target eq 'tex') { @@ -2454,14 +2757,14 @@ sub end_th { # (Note there seems to also be support for this as a % of page size) # sub start_img { - my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_; + my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style) = @_; my $src = &Apache::lonxml::get_param('src',$parstack,$safeeval, undef,1); if (not $src and ($target eq 'web' or $target eq 'tex')) { - my $inside = &Apache::lonxml::get_all_text("/img",$parser); + my $inside = &Apache::lonxml::get_all_text("/img",$parser,$style); return ''; } - $Apache::lonxml::extlinks[$#Apache::lonxml::extlinks+1]=$src; + &Apache::lonxml::extlink($src); my $currentstring = ''; my $scaling = .3; @@ -2469,13 +2772,17 @@ sub start_img { if ($target eq 'web') { if ($env{'browser.imagesuppress'} ne 'on') { - $currentstring.=&Apache::lonenc::encrypt_ref($token,{'src'=>$src}); + my $enc = ('yes' eq + lc(&Apache::lonxml::get_param('encrypturl',$parstack, + $safeeval))); + $currentstring.=&Apache::lonenc::encrypt_ref($token,{'src'=>$src}, + $enc); } else { - my $alttag= &Apache::lonxml::get_param - ('alt',$parstack,$safeeval,undef,1); - unless ($alttag) { - $alttag=&Apache::lonmeta::alttag - ($Apache::lonxml::pwd[-1],$src); + my $alttag = &Apache::lonxml::get_param('alt',$parstack,$safeeval, + undef,1); + if (!$alttag) { + $alttag = &Apache::lonmeta::alttag($Apache::lonxml::pwd[-1], + $src); } $currentstring.='[IMAGE: '.$alttag.']'; } @@ -2494,7 +2801,7 @@ sub start_img { $safeeval, undef,1)); if(!$align) { - $align = "bottom"; # This is html's default so it's ours too. + $align = "bottom"; # This is html's default so it's ours too. } # &Apache::lonxml::debug("Alignemnt = $align"); @@ -2509,11 +2816,18 @@ sub start_img { $parstack, $safeeval, undef,0); - &Apache::lonxml::debug("LaTeX rendering = $latex_rendering"); + # &Apache::lonxml::debug("LaTeX rendering = $latex_rendering"); if(!$latex_rendering) { - $latex_rendering = "parbox"; + $latex_rendering = "texwrap"; + } + # using texwrap inside a table does not work. So, if after all of this, + # texwrap is on, we turn it off if we detect we're in a table: + # + if (($latex_rendering eq 'texwrap') && &is_inside_of($tagstack, "table")) { + $latex_rendering = 'parpic'; } - &Apache::lonxml::debug("LaTeX rendering = $latex_rendering image file: $src"); + + # &Apache::lonxml::debug("LaTeX rendering = $latex_rendering image file: $src"); #if original gif/jpg/png file exist do following: my $origsrc=$src; @@ -2552,16 +2866,17 @@ sub start_img { } elsif ($align eq "left") { if ($latex_rendering eq "parpic") { $currentstring = '\parpic[l]{'.$currentstring.'}'; - } else { # parbox rendering - $currentstring = "\\strut\\newline\n". - '\parbox{'.$width_param.'mm}{'.$currentstring.'}'; + } else { # wrapfig render + $currentstring = '\begin{wrapfigure}{l}{'.$width_param.'mm}' + .'\scalebox{1.0}{'.$currentstring.'}\end{wrapfigure}'; } } elsif ($align eq "right") { if ($latex_rendering eq "parpic") { $currentstring = '\parpic[r]{'.$currentstring.'}'; - } else { # parbox rendering. - $currentstring = '\parbox{'.$width_param.'mm}{\begin{flushright}' - .$currentstring.'\end{flushright}} \newline'."\n"; + } else { # wrapfig rendering + $currentstring = '\begin{wrapfigure}{r}{'.$width_param.'mm}' + .'\scalebox{1.0}{'.$currentstring.'}\end{wrapfigure}'; + } } else { # Bottom is also default. # $currentstring = '\raisebox{'.$height_param.'mm}{'.$currentstring.'}'; @@ -2594,6 +2909,8 @@ sub start_img { ['','bottom','middle','top','left','right'],$token,5); $currentstring .=&Apache::edit::select_arg('TeXwrap:', 'TeXwrap', ['', 'parbox', 'parpic'], $token, 2); + $currentstring .=&Apache::edit::select_arg('Encyrpt URL:','encrypturl', + ['no','yes'], $token, 2); $currentstring .=&Apache::edit::end_row().&Apache::edit::start_spanning_row(); my $src= &Apache::lonxml::get_param('src',$parstack,$safeeval); my $alt= &Apache::lonxml::get_param('alt',$parstack,$safeeval); @@ -2611,7 +2928,7 @@ sub start_img { my $ctag=&Apache::edit::get_new_args($token,$parstack, $safeeval,'src','alt','align', 'TeXwidth','TeXheight', 'TeXwrap', - 'width','height'); + 'width','height','encrypturl'); my ($nsrc,$nwidth,$nheight)= ($token->[2]{'src'},$token->[2]{'width'},$token->[2]{'height'}); my $loc=&Apache::lonnet::filelocation($Apache::lonxml::pwd[-1],$nsrc); @@ -2666,12 +2983,10 @@ sub start_applet { my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_; my $code=&Apache::lonxml::get_param('code',$parstack,$safeeval,undef,1); - $Apache::lonxml::extlinks[$#Apache::lonxml::extlinks+1]=$code; - + &Apache::lonxml::extlink($code); my $archive=&Apache::lonxml::get_param('archive',$parstack,$safeeval, undef,1); - $Apache::lonxml::extlinks[$#Apache::lonxml::extlinks+1]=$archive; - + &Apache::lonxml::extlink($archive); my $currentstring = ''; if ($target eq 'web') { if ($env{'browser.appletsuppress'} ne 'on') { @@ -2717,7 +3032,7 @@ sub end_applet { sub start_embed { my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_; my $src=&Apache::lonxml::get_param('src',$parstack,$safeeval,undef,1); - $Apache::lonxml::extlinks[$#Apache::lonxml::extlinks+1]=$src; + &Apache::lonxml::extlink($src); my $currentstring = ''; if ($target eq 'web') { if ($env{'browser.embedsuppress'} ne 'on') { @@ -2748,13 +3063,15 @@ sub end_embed { #-- tag (end tag forbidden) sub start_param { my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_; - if (&Apache::lonxml::get_param - ('name',$parstack,$safeeval,undef,1)=~/^cabbase$/i) { - $Apache::lonxml::extlinks[$#Apache::lonxml::extlinks+1]= - &Apache::lonxml::get_param('value',$parstack,$safeeval,undef,1); - } - $Apache::lonxml::extlinks[$#Apache::lonxml::extlinks+1]= - &Apache::lonxml::get_param('src',$parstack,$safeeval,undef,1); + if (&Apache::lonxml::get_param('name',$parstack, + $safeeval,undef,1)=~/^cabbase$/i) { + my $value=&Apache::lonxml::get_param('value',$parstack, + $safeeval,undef,1); + &Apache::lonxml::extlink($value); + } + + my $src = &Apache::lonxml::get_param('src',$parstack,$safeeval,undef,1); + &Apache::lonxml::extlink($src); my $currentstring = ''; if ($target eq 'web') { my %toconvert; @@ -2786,9 +3103,8 @@ sub end_param { sub start_allow { my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_; my $src = &Apache::lonxml::get_param('src',$parstack,$safeeval,undef,1); - $src=&Apache::lonnet::filelocation($Apache::lonxml::pwd[-1],$src); - $Apache::lonxml::extlinks[$#Apache::lonxml::extlinks+1]= - &Apache::lonnet::clutter($src); + &Apache::lonxml::extlink($src); + if ($target eq 'tex') { &image_replication($src); } my $result; if ($target eq 'edit') { @@ -2882,11 +3198,12 @@ sub end_xmp { #--

         (end tag required)
         sub start_pre {
             my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
        -    my $currentstring = &end_p;	# close off pending 

        + my $currentstring = &end_p(); # close off pending

        if ($target eq 'web') { $currentstring .= $token->[4]; } elsif ($target eq 'tex') { $currentstring .= '\begin{verbatim}'; + &Apache::lonxml::disable_LaTeX_substitutions(); } return $currentstring; } @@ -2898,6 +3215,7 @@ sub end_pre { $currentstring .= $token->[2]; } elsif ($target eq 'tex') { $currentstring .= '\end{verbatim}'; + &Apache::lonxml::enable_LaTeX_substitutions(); } return $currentstring; } @@ -2945,7 +3263,7 @@ sub end_externallink { #-- sub start_blankspace { my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_; - my $currentstring = &end_p; # closes off any unclosed

        + my $currentstring = &end_p(); # closes off any unclosed

        if ($target eq 'tex') { my $howmuch = &Apache::lonxml::get_param('heigth',$parstack,$safeeval,undef,1); $currentstring .= '\vskip '.$howmuch.' '; @@ -3098,7 +3416,7 @@ sub end_blink { #--

        tag (end tag required) sub start_blockquote { my ($target,$token) = @_; - my $currentstring = &end_p; # Close any unclosed

        + my $currentstring = &end_p(); # Close any unclosed

        if ($target eq 'web') { $currentstring .= $token->[4]; } @@ -3382,9 +3700,12 @@ sub end_legend { #-- tag (end tag forbidden) sub start_link { - my ($target,$token) = @_; + my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_; my $currentstring = ''; if ($target eq 'web') { + my $href=&Apache::lonxml::get_param('href',$parstack,$safeeval, + undef,1); + &Apache::lonxml::extlink($href); $currentstring = $token->[4]; } return $currentstring; @@ -3421,7 +3742,7 @@ sub end_marquee { #-- tag (end tag required) sub start_multicol { my ($target,$token) = @_; - my $currentstring = &end_p; # Close any pending

        + my $currentstring = &end_p(); # Close any pending

        if ($target eq 'web') { $currentstring .= $token->[4]; } @@ -3619,7 +3940,7 @@ sub end_server { #-- tag (end tag forbidden) sub start_spacer { my ($target,$token) = @_; - my $currentstring = &end_p; # Close off any open

        tag. + my $currentstring = &end_p(); # Close off any open

        tag. if ($target eq 'web') { $currentstring .= $token->[4]; } @@ -3900,7 +4221,15 @@ sub image_height { sub get_eps_image { my ($src)=@_; my $orig_src=&Apache::lonnet::filelocation($Apache::lonxml::pwd[-1], $src); + + # In order to prevent the substitution of the alt text, we need to + # be sure the orig_src file is on system now so: + + if (! -e $orig_src) { + &Apache::lonnet::repcopy($orig_src); # Failure is not completely fatal. + } &Apache::lonxml::debug("get_eps_image: Original image: $orig_src"); + my ($spath, $sname, $sext) = fileparse($src, qr/\.(gif|png|jpg|jpeg)/i); $src=~s/\.(gif|png|jpg|jpeg)$/\.eps/i; $src=&Apache::lonnet::filelocation($Apache::lonxml::pwd[-1],$src); &Apache::lonxml::debug("Filelocation gives: $src"); @@ -3929,6 +4258,9 @@ sub get_eps_image { close FILE; $src=~s|/home/httpd/html/res|/home/httpd/prtspool|; $src=~s|/home/([^/]*)/public_html/|/home/httpd/prtspool/$1/|; + if ($sext ne "") { # Put the ext. back in to uniquify. + $src =~ s/\.eps$/$sext.eps/; + } } } } @@ -3968,7 +4300,11 @@ sub file_path { } return $file,$path; } - +# Converts a measurement in to mm from any of +# the other valid LaTeX units of measure. +# If the units of measure are missing from the +# parameter, it is assumed to be in and returned +# with mm units of measure sub recalc { my $argument = shift; if (not $argument=~/(mm|cm|in|pc|pt)/) {return $argument.' mm';} @@ -4013,6 +4349,26 @@ sub LATEX_length { } +# is_inside_of $tagstack $tag +# This sub returns true if the current state of Xml processing +# is inside of the tag. +# Parameters: +# tagstack - The tagstack from the parser. +# tag - The tag (without the <>'s.). +# Sample usage: +# if (is_inside_of($tagstack "table")) { +# # I'm in a table.... +# } +sub is_inside_of { + my ($tagstack, $tag) = @_; + my @stack = @$tagstack; + for (my $i = ($#stack - 1); $i >= 0; $i--) { + if ($stack[$i] eq $tag) { + return 1; + } + } + return 0; +} 1; 500 Internal Server Error

        Internal Server Error

        The server encountered an internal error or misconfiguration and was unable to complete your request.

        Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

        More information about this error may be available in the server error log.