--- loncom/xml/londefdef.pm 2006/03/29 23:00:51 1.302.2.5 +++ loncom/xml/londefdef.pm 2006/08/02 19:26:54 1.332 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Tags Default Definition Module # -# $Id: londefdef.pm,v 1.302.2.5 2006/03/29 23:00:51 albertel Exp $ +# $Id: londefdef.pm,v 1.332 2006/08/02 19:26:54 www Exp $ # # # Copyright Michigan State University Board of Trustees @@ -68,7 +68,6 @@ BEGIN { # for ($row =0; $row <= $lastrow; $row++ ) { # my $text = Dumper($Apache::londefdef::table[$row]); # &Apache::lonnet::logthis("table [ $row ]".$text); -# # } #} sub initialize_londefdef { @@ -80,6 +79,8 @@ sub initialize_londefdef { @Apache::londefdef::DT=(0); @Apache::londefdef::seenDT=(0); $Apache::londefdef::list_index=0; + undef($Apache::londefdef::head); + undef($Apache::londefdef::title); } #======================= TAG SUBROUTINES ===================== @@ -106,11 +107,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:"); @@ -169,16 +180,16 @@ sub end_tthoption { sub start_html { my ($target,$token) = @_; my $currentstring = ''; - my $options=$env{'course.'.$env{'request.course.id'}.'.tthoptions'}; - &Apache::lontexconvert::init_tth(); if ($target eq 'web' || $target eq 'edit' || $target eq 'webgrade' ) { - $currentstring = &Apache::lonxml::xmlbegin(); + # start_body() takes care of emitting the } elsif ($target eq 'tex') { - $currentstring .= '\documentclass[letterpaper]{article}'; + $currentstring .= + '\documentclass[letterpaper,twoside]{article}\raggedbottom'; 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}'. @@ -202,7 +213,7 @@ sub end_html { my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_; my $currentstring = ''; if ($target eq 'web' || $target eq 'webgrade') { - $currentstring = ''; + # end_body takes care of the } return $currentstring; } @@ -212,7 +223,7 @@ sub start_head { my ($target,$token) = @_; my $currentstring = ''; if ($target eq 'web' || $target eq 'webgrade') { - $currentstring = $token->[4].&Apache::lonxml::fontsettings(); + &Apache::lonxml::startredirection(); } return $currentstring; } @@ -222,8 +233,10 @@ sub end_head { my $currentstring = ''; if (($target eq 'web' && $env{'request.state'} eq 'published') || ($target eq 'webgrade' && $env{'request.state'} eq 'published')) { - $currentstring = &Apache::lonmenu::registerurl(undef,$target). - $token->[2]; + # in case there is a but no + if ($Apache::lonxml::redirection) { + $Apache::londefdef::head = &Apache::lonxml::endredirection(); + } } return $currentstring; } @@ -355,10 +368,11 @@ sub end_form { #-- tag (end tag required) sub start_title { - my ($target,$token) = @_; + my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style) = @_; my $currentstring = ''; if ($target eq 'web' || $target eq 'webgrade') { - $currentstring = $token->[4]; + $Apache::londefdef::title = + &Apache::lonxml::get_all_text('/title',$parser,$style); } elsif ($target eq 'tex') { $currentstring .= '\keephidden{Title of the document: ' } @@ -373,7 +387,7 @@ sub end_title { my ($target,$token) = @_; my $currentstring = ''; if ($target eq 'web' || $target eq 'webgrade') { - $currentstring = $token->[2]; + # start_title takes care of swallowing the title } elsif ($target eq 'tex') { $currentstring .= '}'; } @@ -508,74 +522,25 @@ sub start_body { &Apache::lonxml::warning("<body> tag found inside of <problem> tag this can cause problems."); return ''; } - if (!$Apache::lonxml::registered && - $env{'request.state'} eq 'published') { - $currentstring.='<head>'. - &Apache::lonmenu::registerurl(undef,$target).'</head>'; - } -# Accessibility - if ($env{'browser.imagesuppress'} eq 'on') { - delete($token->[2]->{'background'}); - } - if ($env{'browser.fontenhance'} eq 'on') { - my $style=''; - foreach my $key (keys(%{$token->[2]})) { - if ($key =~ /^style$/i) { - $style.=$token->[2]->{$key}.';'; - delete($token->[2]->{$key}); - } - } - $token->[2]->{'style'}=$style.'; font-size: x-large;'; - } - if ($env{'browser.blackwhite'} eq 'on') { - delete($token->[2]->{'font'}); - delete($token->[2]->{'link'}); - delete($token->[2]->{'alink'}); - delete($token->[2]->{'vlink'}); - delete($token->[2]->{'bgcolor'}); - delete($token->[2]->{'background'}); - } -# Overload loads - my $onLoad=''; - foreach my $key (keys(%{$token->[2]})) { - if ($key =~ /^onload$/i) { - $onLoad.=$token->[2]->{$key}.';'; - delete($token->[2]->{$key}); - } - } - $token->[2]->{'onload'}=&Apache::lonmenu::loadevents().';'.$onLoad; - my $onUnload=''; - foreach my $key (keys(%{$token->[2]})) { - if ($key =~ /^onunload$/i) { - $onUnload.=$token->[2]->{$key}.';'; - delete($token->[2]->{$key}); - } - } - $token->[2]->{'onunload'}=&Apache::lonmenu::unloadevents(). - ';'.$onUnload; - $currentstring .= '<'.$token->[1]; - foreach (keys %{$token->[2]}) { - $currentstring.=' '.$_.'="'.$token->[2]->{$_}.'"'; - } - $currentstring.='>'; - &Apache::lontexconvert::jsMath_reset(); - if ($env{'environment.texengine'} eq 'jsMath') { - $currentstring.=&Apache::lontexconvert::jsMath_header(); + if (&is_inside_of($tagstack, "head")) { + &end_head(@_); } + $currentstring = + &Apache::loncommon::start_page($Apache::londefdef::title, + $Apache::londefdef::head, + {'add_entries' => $token->[2], + 'no_title' => 1, + 'force_register' => 1}); + if ($env{'request.state'} ne 'published') { - if ($env{'environment.remote'} eq 'off') { - $currentstring.= - &Apache::lonmenu::constspaceform(). - &Apache::lonmenu::menubuttons(1,'web',1); - } + $currentstring.=&Apache::lonmenu::constspaceform(); $currentstring.=(<<EDITBUTTON); <form method="post"> <input type="submit" name="editmode" accesskey="e" value="Edit" /> </form> +<br /> EDITBUTTON - } else { - $currentstring.=&Apache::lonmenu::menubuttons(undef,$target,1); } $currentstring.=&Apache::lonxml::message_location(); } elsif ($target eq 'tex') { @@ -588,7 +553,7 @@ sub end_body { my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_; my $currentstring = &end_p(); # Close off unclosed <p> if ($target eq 'web' || $target eq 'webgrade') { - $currentstring .= &Apache::lonxml::xmlend($target,$parser); + $currentstring .= &Apache::loncommon::end_page({'discussion' => 1}); } elsif ($target eq 'tex') { $currentstring .= '\strut\newline\noindent\makebox[\textwidth/$number_of_columns][b]{\hrulefill}\newline\noindent \end{document}'; } @@ -620,9 +585,6 @@ sub end_center { $currentstring = $token->[2]; } elsif ($target eq 'tex') { $currentstring = '\end{center}'; - if (&is_inside_of($tagstack, "table")) { - #$currentstring .= ¢er_correction(); - } } return $currentstring; } @@ -1188,6 +1150,7 @@ sub start_p { $closing_string = '</p>'; # Deal correctly with <p /> 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') { @@ -1195,17 +1158,22 @@ sub start_p { $closing_string = '\end{center}'; if (&is_inside_of($tagstack, "table")) { $currentstring = ¢er_correction().$currentstring; - #$closing_string .= ¢er_correction(); } } 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 '; + if (&is_inside_of($tagstack, 'table')) { + $closing_string = '\vskip 0pt'; # Seems to be consistent with <p> in tables. + } else { + $closing_string = '\strut\\\\\strut '; + } } } @@ -1540,7 +1508,6 @@ sub start_div { $endstring = '\end{center}'; if (&is_inside_of($tagstack, "table")) { $currentstring = ¢er_correction().$currentstring; - #$endstring .= ¢er_correction(); } } elsif ($align eq 'right') { @@ -1981,7 +1948,12 @@ sub start_table { $Apache::londefdef::table[-1]{'width'}=$1*$textwidth/100; } else { $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); @@ -2209,7 +2181,38 @@ 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.=¢er_correction().'\begin{center}'; } elsif ($Apache::londefdef::table[-1]{'align'}[$in][$jn] eq 'r') { @@ -2217,13 +2220,43 @@ sub end_table { } $output.=$Apache::londefdef::table[-1]{'content'}[$in][$jn]; if ($Apache::londefdef::table[-1]{'align'}[$in][$jn] eq 'c') { - $output.='\end{center}';#.¢er_correction(); + $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'}.' '; + } } # Note that \newline destroys alignment env's produced by e.g. <div> # $Apache::londefdef::table[-1]{'output'} .= $header_of_table.$Apache::londefdef::table[-1]{'hinc'}.$output.'\end{tabular}\strut\newline\strut '; @@ -2367,8 +2400,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'; @@ -2457,7 +2533,30 @@ sub end_td_tex { } # Should be be killing off the 'include' elements as they're used up? + push @ {$Apache::londefdef::table[-1]{'content'}[-1] },$data; + + + + + # 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 ''; } @@ -2631,13 +2730,17 @@ sub start_img { if ($target eq 'web' || $target eq 'webgrade') { if ($env{'browser.imagesuppress'} ne 'on') { - $currentstring.=&Apache::lonenc::encrypt_ref($token,{'src'=>$src}); - } else { - my $alttag= &Apache::lonxml::get_param - ('alt',$parstack,$safeeval,undef,1); - unless ($alttag) { - $alttag=&Apache::lonmeta::alttag - ($Apache::lonxml::pwd[-1],$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); + if (!$alttag) { + $alttag = &Apache::lonmeta::alttag($Apache::lonxml::pwd[-1], + $src); } $currentstring.='[IMAGE: '.$alttag.']'; } @@ -2656,12 +2759,7 @@ sub start_img { $safeeval, undef,1)); if(!$align) { - # disabled for now see BUG#4535 - if (&is_inside_of($tagstack, "table")) { - $align = "top"; # Force top of image to top of table cell - } else { $align = "bottom"; # This is html's default so it's ours too. - } } # &Apache::lonxml::debug("Alignemnt = $align"); @@ -2676,11 +2774,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 = "texwrap"; + $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; @@ -2762,6 +2867,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('Encrypt 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); @@ -2779,7 +2886,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); @@ -2982,34 +3089,14 @@ sub start_frameset { my ($target,$token) = @_; my $currentstring = ''; # Close any pending para. if ($target eq 'web' || $target eq 'webgrade') { - if (!$Apache::lonxml::registered && - $env{'request.state'} eq 'published') { - $currentstring.='<head>'. - &Apache::lonmenu::registerurl(undef,$target).'</head>'; - } - my $onLoad=''; - foreach my $key (keys(%{$token->[2]})) { - if ($key =~ /^onload$/i) { - $onLoad.=$token->[2]->{$key}.';'; - delete($token->[2]->{$key}); - } - } - $token->[2]->{'onload'}=&Apache::lonmenu::loadevents().';'.$onLoad; - my $onUnload=''; - foreach my $key (keys(%{$token->[2]})) { - if ($key =~ /^onunload$/i) { - $onUnload.=$token->[2]->{$key}.';'; - delete($token->[2]->{$key}); - } - } - $token->[2]->{'onunload'}=&Apache::lonmenu::unloadevents(). - ';'.$onUnload; - - $currentstring .= '<'.$token->[1]; - foreach (keys %{$token->[2]}) { - $currentstring.=' '.$_.'="'.$token->[2]->{$_}.'"'; - } - $currentstring.='>'; + $currentstring = + &Apache::loncommon::start_page($Apache::londefdef::title, + $Apache::londefdef::head, + {'add_entries' => $token->[2], + 'no_title' => 1, + 'force_register' => 1, + 'frameset' => 1,}); + } return $currentstring; } @@ -3054,6 +3141,7 @@ sub start_pre { $currentstring .= $token->[4]; } elsif ($target eq 'tex') { $currentstring .= '\begin{verbatim}'; + &Apache::lonxml::disable_LaTeX_substitutions(); } return $currentstring; } @@ -3065,6 +3153,7 @@ sub end_pre { $currentstring .= $token->[2]; } elsif ($target eq 'tex') { $currentstring .= '\end{verbatim}'; + &Apache::lonxml::enable_LaTeX_substitutions(); } return $currentstring; }