File:  [LON-CAPA] / loncom / xml / londefdef.pm
Revision 1.338: download - view: text, annotated - select for diffs
Mon Sep 25 10:11:47 2006 UTC (17 years, 7 months ago) by foxr
Branches: MAIN
CVS tags: HEAD
Defect 4078 - Honor line break in simple <sup></sup>  Note that
   more complex stuff like <sup><othertag>text <br /></othertag</sup> will,
I think fail to honor the <br /> since it looks like the original
code is only looking for one level out... and to do this really properly
will involve closing all the enclosing tags, inserting the linebreak
and then reopening all the enclosing tags.

    1: # The LearningOnline Network with CAPA
    2: # Tags Default Definition Module 
    3: #
    4: # $Id: londefdef.pm,v 1.338 2006/09/25 10:11:47 foxr Exp $
    5: # 
    6: #
    7: # Copyright Michigan State University Board of Trustees
    8: #
    9: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
   10: #
   11: # LON-CAPA is free software; you can redistribute it and/or modify
   12: # it under the terms of the GNU General Public License as published by
   13: # the Free Software Foundation; either version 2 of the License, or
   14: # (at your option) any later version.
   15: #
   16: # LON-CAPA is distributed in the hope that it will be useful,
   17: # but WITHOUT ANY WARRANTY; without even the implied warranty of
   18: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   19: # GNU General Public License for more details.
   20: #
   21: # You should have received a copy of the GNU General Public License
   22: # along with LON-CAPA; if not, write to the Free Software
   23: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   24: #
   25: # /home/httpd/html/adm/gpl.txt
   26: #
   27: # http://www.lon-capa.org/
   28: ## Copyright for TtHfunc and TtMfunc by Ian Hutchinson. 
   29: # TtHfunc and TtMfunc (the "Code") may be compiled and linked into 
   30: # binary executable programs or libraries distributed by the 
   31: # Michigan State University (the "Licensee"), but any binaries so 
   32: # distributed are hereby licensed only for use in the context
   33: # of a program or computational system for which the Licensee is the 
   34: # primary author or distributor, and which performs substantial 
   35: # additional tasks beyond the translation of (La)TeX into HTML.
   36: # The C source of the Code may not be distributed by the Licensee
   37: # to any other parties under any circumstances.
   38: #
   39: 
   40: package Apache::londefdef; 
   41: 
   42: use Apache::lonnet;
   43: use strict;
   44: use Apache::lonxml;
   45: use Apache::File();
   46: use Image::Magick;
   47: use Apache::lonmenu();
   48: use Apache::lonmeta();
   49: use Apache::Constants qw(:common);
   50: use File::Basename;
   51: # use Data::Dumper;
   52: 
   53: BEGIN {
   54: 
   55:     &Apache::lonxml::register('Apache::londefdef',('a','abbr','acronym','accessrule','address','allow','applet','area','b','base','basefont','bgo','bgsound','big','blink','blockquote','blankspace','body','br','button','caption','center','cite','code','col','colgroup','dd','del','dfn','dir','div','dl','dt','em','embed','externallink','fieldset','font','form','frame','frameset','h1','h2','h3','h4','h5','h6','head','hr','html','i','iframe','img','input','ins','insert','isindex','kbd','keygen','label','layer','legend','li','link','m','map','marquee','menu','meta','multicol','nobr','noembed','noframes','nolayer','noscript','object','ol','optgroup','option','output','p','param','pre','q','s','samp','select','server','small','spacer','span','strike','strong','sub','sup','table','tbody','td','textarea','tfoot','th','thead','title','tr','tt','tthoption','u','ul','var','wbr','hideweboutput'));
   56: 
   57: }
   58: 
   59: #
   60: #   Dumps all elements of the table structure.
   61: #   Need this 'cause evidently when given an array, Data::Dumper only seems
   62: #   to dump element 0.
   63: #
   64: #sub debug_dump_table {
   65: #    my $lastrow = $#Apache::londefdef::table;
   66: #    &Apache::lonnet::logthis("Dumping table:  Last row index: $lastrow");
   67: #    my $row;
   68: #    for ($row =0; $row <= $lastrow; $row++ ) {
   69: #	my $text = Dumper($Apache::londefdef::table[$row]);
   70: #	&Apache::lonnet::logthis("table [ $row ]".$text);
   71: #    }
   72: #}
   73: sub initialize_londefdef {
   74:     $Apache::londefdef::TD_redirection=0;
   75:     @Apache::londefdef::table = ();
   76:     $Apache::londefdef::select=0;
   77:     undef(@Apache::londefdef::description);
   78:     @Apache::londefdef::DD=(0);
   79:     @Apache::londefdef::DT=(0);
   80:     @Apache::londefdef::seenDT=(0);
   81:     $Apache::londefdef::list_index=0;
   82:     undef($Apache::londefdef::head);
   83:     undef($Apache::londefdef::title);
   84: }
   85: 
   86: #======================= TAG SUBROUTINES =====================
   87: #-- <output>
   88: sub start_output {
   89:     my ($target) = @_;
   90:     if ($target eq 'meta') { $Apache::lonxml::metamode--; }
   91:     return '';
   92: }
   93: sub end_output {
   94:     my ($target) = @_;
   95:     if ($target eq 'meta') { $Apache::lonxml::metamode++; }
   96:     return '';
   97: }
   98: #-- <m> tag
   99: sub start_m {
  100:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style) = @_;
  101:     my $currentstring = '';
  102:     my $inside = &Apache::lonxml::get_all_text_unbalanced("/m",$parser);
  103:     if ($target eq 'web' || $target eq 'analyze') {
  104: 	&Apache::lonxml::debug("M is starting with:$inside:");
  105: 	my $eval=&Apache::lonxml::get_param('eval',$parstack,$safeeval);
  106: 	if ($eval eq 'on') {
  107: 	    $inside=&Apache::run::evaluate($inside,$safeeval,$$parstack[-1]);
  108: 	    #&Apache::lonxml::debug("M is evaulated to:$inside:");
  109: 	}
  110: 	my $tex = $inside;
  111: 	my $display=&Apache::lonxml::get_param('display',$parstack,$safeeval);
  112: 	$currentstring = &Apache::lontexconvert::converted(\$inside,$display);
  113: 	if ($Apache::lontexconvert::errorstring) {
  114: 	    my $errormsg='<pre>'.&HTML::Entities::encode($Apache::lontexconvert::errorstring,'<>&"').'</pre> occured while attempting to convert this TeX: <pre>';
  115: 	    $tex = &HTML::Entities::encode($tex,'<>&"');
  116: 	    my ($linenumber) =
  117: 		($Apache::lontexconvert::errorstring =~ /Line (\d+)/);
  118: 	    if (defined($linenumber)) {
  119: 		my @tex=split("\n",$tex);
  120: 		$tex[$linenumber]='<b><font color="red">'.
  121: 		    $tex[$linenumber].'</font></b>';
  122: 		$tex=join("\n",@tex);
  123: 	    }
  124: 	    &Apache::lonxml::warning($errormsg.$tex.'</pre>');
  125: 	    $Apache::lontexconvert::errorstring='';
  126: 	}
  127: 	#&Apache::lonxml::debug("M is ends with:$currentstring:");
  128: 	$Apache::lonxml::post_evaluate=0;
  129:     } elsif ($target eq 'tex') {
  130: 	$currentstring = $inside;
  131: 	my $eval=&Apache::lonxml::get_param('eval',$parstack,$safeeval);
  132: 	if ($eval eq 'on') {
  133: 	    $currentstring=&Apache::run::evaluate($currentstring,$safeeval,$$parstack[-1]);
  134: 	}
  135: 	if ($currentstring=~/^(\s*\\\\\s*)*$/) {$currentstring = ' \vskip 0 mm ';}
  136: 	# detect simple math mode entry exits, and convert them
  137:         # to use \ensuremath
  138: 	if ($currentstring=~/^\s*\$[^\$].*[^\$]\$\s*$/) {
  139: 	    $currentstring=~s/^(\s*)\$/$1/;
  140: 	    $currentstring=~s/\$(\s*)$/$1/;
  141: 	    $currentstring='\ensuremath{'.$currentstring.'}';
  142: 	}
  143: 	$Apache::lonxml::post_evaluate=0;
  144:     }
  145:     return $currentstring;
  146: }
  147: 
  148: sub end_m {
  149:     my ($target,$token) = @_;
  150:     my $currentstring = '';
  151:     if ($target eq 'tex') {
  152: 	$currentstring = "";
  153:     }
  154:     return $currentstring;
  155: }
  156: 
  157: sub start_tthoption {
  158:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style) = @_;
  159:     my $result;
  160:     if ($target eq 'web' || $target eq 'webgrade') {
  161: 	my $inside = &Apache::lonxml::get_all_text("/tthoption",$parser,
  162: 						   $style);
  163: 	$inside=~s/^\s*//;
  164: 	if ($env{'browser.mathml'}) {
  165: 	    &tth::ttmoptions($inside);
  166: 	} else {
  167: 	    &tth::tthoptions($inside);
  168: 	}
  169:     }
  170:     return $result;
  171: }
  172: 
  173: sub end_tthoption {
  174:     my ($target,$token) = @_;
  175:     my $result;
  176:     return $result;
  177: }
  178: 
  179: #-- <html> tag (end tag optional)
  180: sub start_html {
  181:     my ($target,$token) = @_;
  182:     my $currentstring = '';
  183:     if ($target eq 'web' || $target eq 'edit' || $target eq 'webgrade' ) {
  184: 	# start_body() takes care of emitting the <html> 
  185:     } elsif ($target eq 'tex') {
  186: 	$currentstring .= 
  187: 	    '\documentclass[letterpaper,twoside]{article}\raggedbottom';
  188: 	if (($env{'form.latex_type'}=~'batchmode') ||
  189:             (!$env{'request.role.adv'})) {$currentstring .='\batchmode';} 
  190: 	$currentstring .= '\newcommand{\keephidden}[1]{}'.
  191:                           '\renewcommand{\deg}{$^{\circ}$}'.
  192: 			  '\usepackage{multirow}'.
  193:                           '\usepackage{longtable}'.
  194:                           '\usepackage{textcomp}'.
  195:                           '\usepackage{makeidx}'.
  196:                           '\usepackage[dvips]{graphicx}'.
  197: 			  '\usepackage{wrapfig}'.
  198: 			  '\usepackage{picins}'.
  199:                           '\usepackage{epsfig}'.
  200:                           '\usepackage{calc}'.
  201:                           '\usepackage{amsmath}'.
  202:                           '\usepackage{amssymb}'.
  203:                           '\usepackage{amsfonts}'.
  204:                           '\usepackage{amsthm}'.
  205:                           '\usepackage{amscd}'.
  206:                           '\newenvironment{choicelist}{\begin{list}{}{\setlength{\rightmargin}{0in}\setlength{\leftmargin}{0.13in}\setlength{\topsep}{0.05in}\setlength{\itemsep}{0.022in}\setlength{\parsep}{0in}\setlength{\belowdisplayskip}{0.04in}\setlength{\abovedisplayskip}{0.05in}\setlength{\abovedisplayshortskip}{-0.04in}\setlength{\belowdisplayshortskip}{0.04in}}}{\end{list}}'.
  207:                           '\renewenvironment{theindex}{\begin{list}{}{{\vskip 1mm \noindent \large\textbf{Index}} \newline \setlength{\rightmargin}{0in}\setlength{\leftmargin}{0.13in}\setlength{\topsep}{0.01in}\setlength{\itemsep}{0.1in}\setlength{\parsep}{-0.02in}\setlength{\belowdisplayskip}{0.01in}\setlength{\abovedisplayskip}{0.01in}\setlength{\abovedisplayshortskip}{-0.04in}\setlength{\belowdisplayshortskip}{0.01in}}}{\end{list}}';
  208:     }
  209:     return $currentstring;
  210: }
  211: 
  212: sub end_html {
  213:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
  214:     my $currentstring = '';
  215:     if ($target eq 'web' || $target eq 'webgrade') {
  216: 	# end_body takes care of the </html>
  217:     }
  218:     return $currentstring;
  219: }
  220: 
  221: #-- <head> tag (end tag optional)
  222: sub start_head {
  223:     my ($target,$token) = @_;
  224:     my $currentstring = '';
  225:     if ($target eq 'web' || $target eq 'webgrade') {
  226: 	&Apache::lonxml::startredirection();
  227:     } 
  228:     return $currentstring;
  229: }
  230: 
  231: sub end_head {
  232:     my ($target,$token) = @_;
  233:     my $currentstring = '';
  234:     if (($target eq 'web'      && $env{'request.state'} eq 'published') ||
  235: 	($target eq 'webgrade' && $env{'request.state'} eq 'published')) {
  236: 	# in case there is a </head> but no <head>
  237: 	if ($Apache::lonxml::redirection) {
  238: 	    $Apache::londefdef::head = &Apache::lonxml::endredirection();
  239: 	}
  240:     } 
  241:     return $currentstring;
  242: }
  243: 
  244: #-- <map> tag (end tag required)
  245: sub start_map {
  246:     my ($target,$token) = @_;
  247:     my $currentstring = '';
  248:     if ($target eq 'web' || $target eq 'webgrade') {
  249: 	$currentstring = $token->[4];     
  250:     } 
  251:     return $currentstring;
  252: }
  253: 
  254: sub end_map {
  255:     my ($target,$token) = @_;
  256:     my $currentstring = '';
  257:     if ($target eq 'web' || $target eq 'webgrade') {
  258: 	$currentstring = $token->[2];    
  259:     } 
  260:     return $currentstring;
  261: }
  262: 
  263: #-- <select> tag (end tag required)
  264: sub start_select {
  265:     my ($target,$token) = @_;
  266:     my $currentstring = '';
  267:     if ($target eq 'web' || $target eq 'webgrade') {
  268: 	$currentstring = $token->[4];     
  269:     }  elsif ($target eq 'tex') {
  270: 	$Apache::londefdef::select=0;
  271:     }
  272:     return $currentstring;
  273: }
  274: 
  275: sub end_select {
  276:     my ($target,$token) = @_;
  277:     my $currentstring = '';
  278:     if ($target eq 'web' || $target eq 'webgrade') {
  279: 	$currentstring = $token->[2];    
  280:     } 
  281:     return $currentstring;
  282: }
  283: 
  284: #-- <option> tag (end tag optional)
  285: sub start_option {
  286:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
  287:     my $currentstring = '';
  288:     if ($target eq 'web' || $target eq 'webgrade') {
  289: 	$currentstring = $token->[4];     
  290:     } elsif ($target eq 'tex') {
  291: 	$Apache::londefdef::select++;
  292: 	if ($Apache::londefdef::select == 1) {
  293: 	    $currentstring='\noindent\fbox{'.&Apache::lonxml::get_param('value',$parstack,$safeeval).'}\keephidden{';
  294: 	} else {
  295: 	    $currentstring='\keephidden{';
  296: 	}
  297:     }
  298:     return $currentstring;
  299: }
  300: 
  301: sub end_option {
  302:     my ($target,$token) = @_;
  303:     my $currentstring = '';
  304:     if ($target eq 'web' || $target eq 'webgrade') {
  305: 	$currentstring = $token->[2];    
  306:     }  elsif ($target eq 'tex') {
  307: 	$currentstring='}';
  308:     }
  309:     return $currentstring;
  310: }
  311: 
  312: #-- <input> tag (end tag forbidden)
  313: sub start_input {
  314:     my ($target,$token) = @_;
  315:     my $currentstring = '';
  316:     if ($target eq 'web' || $target eq 'webgrade') {
  317: 	$currentstring = $token->[4];     
  318:     } 
  319:     return $currentstring;
  320: }
  321: 
  322: sub end_input {
  323:     my ($target,$token) = @_;
  324:     my $currentstring = '';
  325:     if ($target eq 'web' || $target eq 'webgrade') {
  326: 	$currentstring = $token->[2];    
  327:     } 
  328:     return $currentstring;
  329: }
  330: 
  331: #-- <textarea> tag (end tag required)
  332: sub start_textarea {
  333:     my ($target,$token) = @_;
  334:     my $currentstring = '';
  335:     if ($target eq 'web' || $target eq 'webgrade') {
  336: 	$currentstring = $token->[4];     
  337:     } 
  338:     return $currentstring;
  339: }
  340: 
  341: sub end_textarea {
  342:     my ($target,$token) = @_;
  343:     my $currentstring = '';
  344:     if ($target eq 'web' || $target eq 'webgrade') {
  345: 	$currentstring = $token->[2];    
  346:     } 
  347:     return $currentstring;
  348: }
  349: 
  350: #-- <form> tag (end tag required)
  351: sub start_form {
  352:     my ($target,$token) = @_;
  353:     my $currentstring = '';
  354:     if ($target eq 'web' || $target eq 'webgrade') {
  355: 	$currentstring = $token->[4];     
  356:     } 
  357:     return $currentstring;
  358: }
  359: 
  360: sub end_form {
  361:     my ($target,$token) = @_;
  362:     my $currentstring = '';
  363:     if ($target eq 'web' || $target eq 'webgrade') {
  364: 	$currentstring = $token->[2];    
  365:     } 
  366:     return $currentstring;
  367: }
  368: 
  369: #-- <title> tag (end tag required)
  370: sub start_title {
  371:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style) = @_;
  372:     my $currentstring = '';
  373:     if ($target eq 'web' || $target eq 'webgrade') {
  374: 	$Apache::londefdef::title = 
  375: 	    &Apache::lonxml::get_all_text('/title',$parser,$style);
  376:     } elsif ($target eq 'tex') {
  377: 	$currentstring .= '\keephidden{Title of the document:  ' 
  378:     }
  379:     if ($target eq 'meta') {
  380: 	$currentstring='<title>';
  381: 	&start_output($target);
  382:     }
  383:     return $currentstring;
  384: }
  385: 
  386: sub end_title {
  387:     my ($target,$token) = @_;
  388:     my $currentstring = '';
  389:     if ($target eq 'web' || $target eq 'webgrade') {
  390: 	# start_title takes care of swallowing the title
  391:     } elsif ($target eq 'tex') {
  392: 	$currentstring .= '}';
  393:     }  
  394:     if ($target eq 'meta') {
  395: 	&end_output($target);
  396: 	$currentstring='</title>';
  397:     } 
  398:     return $currentstring;
  399: }
  400: 
  401: #-- <meta> tag (end tag forbidden)
  402: sub start_meta {
  403:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style) = @_;
  404:     my $currentstring = '';
  405:     if ($target eq 'web' || $target eq 'webgrade') {
  406: 	my $args='';
  407: 	if ( $#$parstack > -1 ) { $args=$$parstack[$#$parstack]; }
  408: 	if ($args eq '') {
  409: 	    &Apache::lonxml::get_all_text("/meta",$parser,$style);
  410: 	} else {
  411: 	    $currentstring = $token->[4];
  412: 	}
  413:     } elsif ($target eq 'meta') {
  414: 	unless (&Apache::lonxml::get_param
  415: 		('http-equiv',$parstack,$safeeval,undef,1)) {
  416: 	    my $name=$token->[2]->{'name'};
  417: 	    $name=~tr/A-Z/a-z/;
  418: 	    $name=~s/\s/\_/gs;
  419: 	    $name=~s/\W//gs;
  420: 	    if ($name) {
  421: 		$currentstring='<'.$name;
  422:                  my $display=&Apache::lonxml::get_param
  423: 		('display',$parstack,$safeeval,undef,1);
  424:                 if ($display) {
  425:                     $display=~s/\"/\'/g;
  426: 		    $currentstring.=' display="'.$display.'"';
  427:                 }
  428: 		$currentstring.='>'.
  429: 		    &Apache::lonxml::get_param
  430: 			('content',$parstack,$safeeval,undef,1).
  431: 			'</'.$name.'>';
  432: 	    }
  433:             my $display=&Apache::lonxml::get_param
  434: 		('display',$parstack,$safeeval,undef,1);
  435:             if ($display) {
  436: 		$display=&HTML::Entities::encode($display,'<>&"');
  437: 		$currentstring.='<'.$name.'.display>'.$display.
  438:                                '</'.$name.'.display>';
  439:             }
  440: 	}
  441:     } elsif ($target eq 'tex') {
  442: 	my $content=&Apache::lonxml::get_param('content',$parstack,$safeeval);
  443: 	my $name=&Apache::lonxml::get_param('name',$parstack,$safeeval);
  444: 	if ((not defined $content) && (not defined $name)) {
  445: 	    &Apache::lonxml::startredirection();
  446: 	}
  447:     }
  448:     return $currentstring;
  449: }
  450: 
  451: sub end_meta {
  452:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
  453:     my $currentstring = '';
  454:     if ($target eq 'web' || $target eq 'webgrade') {
  455: 	my $args='';
  456: 	if ( $#$parstack > -1 ) { $args=$$parstack[$#$parstack]; }
  457: 	if ($args ne '') {
  458: 	    $currentstring = $token->[4];
  459: 	}
  460:     } elsif ($target eq 'tex') {
  461: 	my $content=&Apache::lonxml::get_param('content',$parstack,$safeeval);
  462: 	my $name=&Apache::lonxml::get_param('name',$parstack,$safeeval);
  463: 	if ((not defined $content) && (not defined $name)) {
  464: 	    &Apache::lonxml::endredirection();
  465: 	}
  466:     }
  467:     return $currentstring;
  468: }
  469: 
  470: # accessrule
  471: sub start_accessrule {
  472:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style) = @_;
  473:     my $currentstring = '';
  474:     my $eff=&Apache::lonxml::get_param
  475: 	('effect',$parstack,$safeeval,undef,1);
  476:     my $realm=&Apache::lonxml::get_param
  477: 	('realm',$parstack,$safeeval,undef,1);
  478:     my $role=&Apache::lonxml::get_param
  479: 	('role',$parstack,$safeeval,undef,1);
  480:     $realm=~s/\s+//g;
  481:     $realm=~s/\//\_/g;
  482:     $realm=~s/^\_//;
  483:     $realm=~s/\W/\;/g;
  484:     $role=~s/\s+//g;
  485:     $role=~s/\//\_/g;
  486:     $role=~s/\W/\;/g;
  487:     if ($target eq 'web') {
  488: 	my $args='';
  489: 	if ( $#$parstack > -1 ) { $args=$$parstack[$#$parstack]; }
  490: 	if ($args eq '') {
  491: 	    &Apache::lonxml::get_all_text("/accessrule",$parser,$style);
  492: 	} else {
  493: 	    $currentstring = $token->[4];
  494: 	}
  495:     }
  496:     if ($target eq 'meta') {
  497: 	$currentstring='<rule>'.$eff.':'.$realm.':'.$role.'</rule>';
  498:     }
  499:     return $currentstring;
  500: }
  501: 
  502: sub end_accessrule {
  503:     my ($target,$token,$tagstack,$parstack,$parser) = @_;
  504:     my $currentstring = '';
  505:     if ($target eq 'web') {
  506: 	my $args='';
  507: 	if ( $#$parstack > -1 ) { $args=$$parstack[$#$parstack]; }
  508: 	if ($args ne '') {
  509: 	    $currentstring = $token->[4];
  510: 	}
  511:     } 
  512:     return $currentstring;
  513: }
  514: 
  515: #-- <body> tag (end tag required)
  516: sub start_body {
  517:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
  518:     my $currentstring = '';
  519: 
  520:     if ($target eq 'web' || $target eq 'webgrade') {
  521: 	if ($Apache::lonhomework::parsing_a_problem) {
  522: 	    &Apache::lonxml::warning("<body> tag found inside of <problem> tag this can cause problems.");
  523: 	    return '';
  524: 	}
  525: 	
  526: 	if (&is_inside_of($tagstack, "head")) {
  527: 	    &end_head(@_);
  528: 	}
  529: 	$currentstring = 
  530: 	    &Apache::loncommon::start_page($Apache::londefdef::title,
  531: 					   $Apache::londefdef::head,
  532: 					   {'add_entries'    => $token->[2],
  533: 					    'no_title'       => 1,
  534: 					    'force_register' => 1});
  535: 
  536: 	if ($env{'request.state'} ne 'published') {
  537: 	    $currentstring.=&Apache::lonmenu::constspaceform();
  538: 	    $currentstring.=(<<EDITBUTTON);
  539: <form method="post">
  540: <input type="submit" name="editmode" accesskey="e" value="Edit" />
  541: </form>
  542: <br />
  543: EDITBUTTON
  544: 	}
  545: 	$currentstring.=&Apache::lonxml::message_location();
  546:     } elsif ($target eq 'tex') {
  547: 	$currentstring = '\begin{document}';  
  548:     } 
  549:     return $currentstring;
  550: }
  551: 
  552: sub end_body {
  553:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
  554:     my $currentstring = &end_p();	# Close off unclosed <p>
  555:     if ($target eq 'web' || $target eq 'webgrade') {
  556: 	$currentstring .= &Apache::loncommon::end_page({'discussion' => 1});
  557:     } elsif ($target eq 'tex') {
  558: 	$currentstring .= '\strut\newline\noindent\makebox[\textwidth/$number_of_columns][b]{\hrulefill}\newline\noindent \end{document}';  
  559:     } 
  560:     return $currentstring;
  561: }
  562: 
  563: # \begin{center} causes a new paragprah spacing that looks odd inside 
  564: # of a table cell.  Same at the end of a \center but with a slightly
  565: # larger space .. hence center_correction and center_end_correction.
  566: #
  567: sub center_correction { return '\vspace*{-6 mm}'; } 
  568: sub center_end_correction { return '\vspace*{-7 mm}'; }
  569: 
  570: #-- <center> tag (end tag required)
  571: sub start_center {
  572:     my ($target,$token,$tagstack) = @_;
  573:     my $currentstring = &end_p();	# Close off any prior para.
  574:     if ($target eq 'web' || $target eq 'webgrade') {
  575: 	$currentstring .= $token->[4];     
  576:     } elsif ($target eq 'tex') {
  577: 	if (&is_inside_of($tagstack, "table")) {
  578: 	    $currentstring .= &center_correction();
  579: 	}
  580: 	$currentstring .= '\begin{center}';  
  581:     }
  582:     return $currentstring;
  583: }
  584: 
  585: sub end_center {
  586:     my ($target,$token,$tagstack) = @_;
  587:     my $currentstring = '';
  588:     if ($target eq 'web' || $target eq 'webgrade') {
  589: 	$currentstring = $token->[2];     
  590:     } elsif ($target eq 'tex') {
  591: 	$currentstring = '\end{center}';  
  592: 	if (&is_inside_of($tagstack, "table")) {
  593: 	    $currentstring .= &center_end_correction();
  594: 	}
  595:     }
  596:     return $currentstring;
  597: }
  598: 
  599: #-- <b> tag (end tag required)
  600: #      NOTE: In TeX mode disables internal <p>
  601: sub start_b {
  602:     my ($target,$token) = @_;
  603:     my $currentstring = '';
  604:     if ($target eq 'web' || $target eq 'webgrade') {
  605: 	$currentstring = $token->[4];     
  606:     } elsif ($target eq 'tex') {
  607: 	&disable_para();
  608: 	$currentstring .= '\textbf{';  
  609:     } 
  610:     return $currentstring;
  611: }
  612: 
  613: sub end_b {
  614:     my ($target,$token) = @_;
  615:     my $currentstring = '';
  616:     if ($target eq 'web' || $target eq 'webgrade') {
  617: 	$currentstring = $token->[2];     
  618:     } elsif ($target eq 'tex') {
  619: 	&enable_para();
  620: 	$currentstring = '}';
  621:     } 
  622:     return $currentstring;
  623: }
  624: 
  625: #-- <strong> tag (end tag required)
  626: #    NOTE: in TeX mode disables internal <p>
  627: sub start_strong {
  628:     my ($target,$token) = @_;
  629:     my $currentstring = '';
  630:     if ($target eq 'web' || $target eq 'webgrade') {
  631: 	$currentstring = $token->[4];     
  632:     } elsif ($target eq 'tex') {
  633: 	&disable_para();
  634: 	$currentstring = '\textbf{';  
  635:     } 
  636:     return $currentstring;
  637: }
  638: 
  639: sub end_strong {
  640:     my ($target,$token) = @_;
  641:     my $currentstring = '';
  642:     if ($target eq 'web' || $target eq 'webgrade') {	
  643: 	$currentstring = $token->[2];     
  644:     } elsif ($target eq 'tex') {
  645: 	&enable_para();
  646: 	$currentstring = '}';  
  647:     }
  648:     return $currentstring;
  649: }
  650: 
  651: #-- <h1> tag (end tag required)
  652: sub start_h1 {
  653:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
  654:     my $currentstring = &end_p();	# Close off any prior para.
  655:     if ($target eq 'web' || $target eq 'webgrade') {
  656: 	$currentstring .= $token->[4];
  657:     } elsif ($target eq 'tex') {
  658: 	my $pre;
  659: 	my $align=lc(&Apache::lonxml::get_param('align',$parstack,$safeeval,undef,1));
  660: 	if ($align eq 'center') {
  661: 	    $pre='\begin{center}';
  662: 	} elsif ($align eq 'left') {
  663: 	    $pre='\rlap{';
  664: 	} elsif ($align eq 'right') {
  665: 	    $pre=' \hfill \llap{';
  666: 	}
  667: 	my $TeXsize=&Apache::lonxml::get_param('TeXsize',$parstack,$safeeval,undef,0);
  668: 	if (not defined $TeXsize) {$TeXsize="large";}
  669: 	$currentstring .= '\strut\newline '.$pre.'{\\'.$TeXsize.' \textbf{'; 
  670:     } elsif ($target eq 'meta') {
  671: 	$currentstring.='<subject>';
  672: 	&start_output($target);
  673:     }
  674:     return $currentstring;
  675: }
  676: 
  677: sub end_h1 {
  678:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
  679:     my $currentstring = '';
  680:     if ($target eq 'web' || $target eq 'webgrade') {
  681: 	$currentstring .= $token->[2];
  682:     } elsif ($target eq 'tex') {
  683: 	my $post='\vskip 0 mm ';
  684: 	my $align=&Apache::lonxml::get_param('align',$parstack,$safeeval,undef,1);
  685: 	if ($align eq 'center') {
  686: 	    $post='\end{center}';
  687: 	} elsif ($align eq 'left') {
  688: 	    $post='} \hfill'.'\vskip 0 mm ';
  689: 	} elsif ($align eq 'right') {
  690: 	    $post='}'.'\vskip 0 mm ';
  691: 	}
  692: 	$currentstring .= '}}'.$post;
  693:     } elsif ($target eq 'meta') {
  694: 	&end_output($target);
  695: 	$currentstring='</subject>';
  696:     } 
  697:     return $currentstring;
  698: }
  699: 
  700: #-- <h2> tag
  701: sub start_h2 {
  702:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
  703:     my $currentstring = &end_p();	# Close off any prior para.
  704:     if ($target eq 'web' || $target eq 'webgrade') {
  705: 	$currentstring .= $token->[4];
  706:     } elsif ($target eq 'tex') {
  707: 	my $pre;
  708: 	my $align=&Apache::lonxml::get_param('align',$parstack,$safeeval,undef,1);
  709: 	if ($align eq 'center') {
  710: 	    $pre='\begin{center}';
  711: 	} elsif ($align eq 'left') {
  712: 	    $pre='\rlap{';
  713: 	} elsif ($align eq 'right') {
  714: 	    $pre=' \hfill \llap{';
  715: 	}
  716: 	my $TeXsize=&Apache::lonxml::get_param('TeXsize',$parstack,$safeeval,undef,0);
  717: 	if (not defined $TeXsize) {$TeXsize="large";}
  718: 	$currentstring .= '\strut\newline '.$pre.'{\\'.$TeXsize.' \textbf{'; 
  719:     } 
  720:     return $currentstring;
  721: }
  722: 
  723: sub end_h2 {
  724:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
  725:     my $currentstring = '';
  726:     if ($target eq 'web' || $target eq 'webgrade') {
  727: 	$currentstring .= $token->[2];
  728:     } elsif ($target eq 'tex') {
  729: 	my $post='\vskip 0 mm ';
  730: 	my $align=&Apache::lonxml::get_param('align',$parstack,$safeeval,undef,1);
  731: 	if ($align eq 'center') {
  732: 	    $post='\end{center}';
  733: 	} elsif ($align eq 'left') {
  734: 	    $post='} \hfill'.'\vskip 0 mm ';
  735: 	} elsif ($align eq 'right') {
  736: 	    $post='}'.'\vskip 0 mm ';
  737: 	}
  738: 	$currentstring .= '}}'.$post;
  739:     } 
  740:     return $currentstring;
  741: }
  742: 
  743: #-- <h3> tag
  744: sub start_h3 {
  745:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
  746:     my $currentstring = &end_p();	# Close off any prior para.
  747:     if ($target eq 'web' || $target eq 'webgrade') {
  748: 	$currentstring .= $token->[4];
  749:     } elsif ($target eq 'tex') {
  750: 	my $pre;
  751: 	my $align=&Apache::lonxml::get_param('align',$parstack,$safeeval,undef,1);
  752: 	if ($align eq 'center') {
  753: 	    $pre='\begin{center}';
  754: 	} elsif ($align eq 'left') {
  755: 	    $pre='\rlap{';
  756: 	} elsif ($align eq 'right') {
  757: 	    $pre=' \hfill \llap{';
  758: 	}
  759: 	my $TeXsize=&Apache::lonxml::get_param('TeXsize',$parstack,$safeeval,undef,0);
  760: 	if (not defined $TeXsize) {$TeXsize="large";}
  761: 	$currentstring .= '\strut\newline '.$pre.'{\\'.$TeXsize.' \textbf{'; 
  762:     } 
  763:     return $currentstring;
  764: }
  765: 
  766: sub end_h3 {
  767:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
  768:     my $currentstring = '';
  769:     if ($target eq 'web' || $target eq 'webgrade') {
  770: 	$currentstring .= $token->[2];
  771:     } elsif ($target eq 'tex') {
  772: 	my $post='\vskip 0 mm ';
  773: 	my $align=&Apache::lonxml::get_param('align',$parstack,$safeeval,undef,1);
  774: 	if ($align eq 'center') {
  775: 	    $post='\end{center}';
  776: 	} elsif ($align eq 'left') {
  777: 	    $post='} \hfill'.'\vskip 0 mm ';
  778: 	} elsif ($align eq 'right') {
  779: 	    $post='}'.'\vskip 0 mm ';
  780: 	}
  781: 	$currentstring .= '}}'.$post;
  782:     } 
  783:     return $currentstring;
  784: }
  785: 
  786: #-- <h4> tag
  787: sub start_h4 {
  788:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
  789:     my $currentstring = &end_p();	# Close off any prior para.
  790:     if ($target eq 'web' || $target eq 'webgrade') {
  791: 	$currentstring .= $token->[4];
  792:     } elsif ($target eq 'tex') {
  793: 	my $pre;
  794: 	my $align=&Apache::lonxml::get_param('align',$parstack,$safeeval,undef,1);
  795: 	if ($align eq 'center') {
  796: 	    $pre='\begin{center}';
  797: 	} elsif ($align eq 'left') {
  798: 	    $pre='\rlap{';
  799: 	} elsif ($align eq 'right') {
  800: 	    $pre=' \hfill \llap{';
  801: 	}
  802: 	my $TeXsize=&Apache::lonxml::get_param('TeXsize',$parstack,$safeeval,undef,0);
  803: 	if (not defined $TeXsize) {$TeXsize="large";}
  804: 	$currentstring .= '\strut\newline '.$pre.'{\\'.$TeXsize.' \textbf{'; 
  805:     } 
  806:     return $currentstring;
  807: }
  808: 
  809: sub end_h4 {
  810:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
  811:     my $currentstring = '';
  812:     if ($target eq 'web' || $target eq 'webgrade') {
  813: 	$currentstring .= $token->[2];
  814:     } elsif ($target eq 'tex') {
  815: 	my $post='\vskip 0 mm ';
  816: 	my $align=&Apache::lonxml::get_param('align',$parstack,$safeeval,undef,1);
  817: 	if ($align eq 'center') {
  818: 	    $post='\end{center}';
  819: 	} elsif ($align eq 'left') {
  820: 	    $post='} \hfill'.'\vskip 0 mm ';
  821: 	} elsif ($align eq 'right') {
  822: 	    $post='}'.'\vskip 0 mm ';
  823: 	}
  824: 	$currentstring .= '}}'.$post;
  825:     } 
  826:     return $currentstring;
  827: }
  828: 
  829: #-- <h5> tag
  830: sub start_h5 {
  831:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
  832:     my $currentstring = &end_p();	# Close off any prior paras.
  833:     if ($target eq 'web' || $target eq 'webgrade') {
  834: 	$currentstring .= $token->[4];
  835:     } elsif ($target eq 'tex') {
  836: 	my $pre;
  837: 	my $align=&Apache::lonxml::get_param('align',$parstack,$safeeval,undef,1);
  838: 	if ($align eq 'center') {
  839: 	    $pre='\begin{center}';
  840: 	} elsif ($align eq 'left') {
  841: 	    $pre='\rlap{';
  842: 	} elsif ($align eq 'right') {
  843: 	    $pre=' \hfill \llap{';
  844: 	}
  845: 	my $TeXsize=&Apache::lonxml::get_param('TeXsize',$parstack,$safeeval,undef,0);
  846: 	if (not defined $TeXsize) {$TeXsize="large";}
  847: 	$currentstring .= '\strut\newline '.$pre.'{\\'.$TeXsize.' \textbf{'; 
  848:     } 
  849:     return $currentstring;
  850: }
  851: 
  852: sub end_h5 {
  853:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
  854:     my $currentstring = '';
  855:     if ($target eq 'web' || $target eq 'webgrade') {
  856: 	$currentstring .= $token->[2];
  857:     } elsif ($target eq 'tex') {
  858: 	my $post='\vskip 0 mm ';
  859: 	my $align=&Apache::lonxml::get_param('align',$parstack,$safeeval,undef,1);
  860: 	if ($align eq 'center') {
  861: 	    $post='\end{center}';
  862: 	} elsif ($align eq 'left') {
  863: 	    $post='} \hfill'.'\vskip 0 mm ';
  864: 	} elsif ($align eq 'right') {
  865: 	    $post='}'.'\vskip 0 mm ';
  866: 	}
  867: 	$currentstring .= '}}'.$post;
  868:     } 
  869:     return $currentstring;
  870: }
  871: 
  872: #-- <h6> tag
  873: sub start_h6 {
  874:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
  875:     my $currentstring = &end_p();	# Close off any prior paras.
  876:     if ($target eq 'web' || $target eq 'webgrade') {
  877: 	$currentstring .= $token->[4];
  878:     } elsif ($target eq 'tex') {
  879: 	my $pre;
  880: 	my $align=&Apache::lonxml::get_param('align',$parstack,$safeeval,undef,1);
  881: 	if ($align eq 'center') {
  882: 	    $pre='\begin{center}';
  883: 	} elsif ($align eq 'left') {
  884: 	    $pre='\rlap{';
  885: 	} elsif ($align eq 'right') {
  886: 	    $pre=' \hfill \llap{';
  887: 	}
  888: 	my $TeXsize=&Apache::lonxml::get_param('TeXsize',$parstack,$safeeval,undef,0);
  889: 	if (not defined $TeXsize) {$TeXsize="large";}
  890: 	$currentstring .= '\strut\newline '.$pre.'{\\'.$TeXsize.' \textbf{'; 
  891:     } 
  892:     return $currentstring;
  893: }
  894: 
  895: sub end_h6 {
  896:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
  897:     my $currentstring = '';
  898:     if ($target eq 'web' || $target eq 'webgrade') {
  899: 	$currentstring .= $token->[2];
  900:     } elsif ($target eq 'tex') {
  901: 	my $post='\vskip 0 mm ';
  902: 	my $align=&Apache::lonxml::get_param('align',$parstack,$safeeval,undef,1);
  903: 	if ($align eq 'center') {
  904: 	    $post='\end{center}';
  905: 	} elsif ($align eq 'left') {
  906: 	    $post='} \hfill'.'\vskip 0 mm ';
  907: 	} elsif ($align eq 'right') {
  908: 	    $post='}'.'\vskip 0 mm ';
  909: 	}
  910: 	$currentstring .= '}}'.$post;
  911:     } 
  912:     return $currentstring;
  913: }
  914: 
  915: #--- <cite> tag (end tag required)
  916: sub start_cite {
  917:     my ($target,$token) = @_;
  918:     my $currentstring = '';
  919:     if ($target eq 'web' || $target eq 'webgrade') {
  920: 	$currentstring .= $token->[4];
  921:     } elsif ($target eq 'tex') {
  922: 	$currentstring .= '\textit{';
  923:     }
  924:     return $currentstring;
  925: }
  926: 
  927: sub end_cite {
  928:     my ($target,$token) = @_;
  929:     my $currentstring = '';
  930:     if ($target eq 'web' || $target eq 'webgrade') {
  931: 	$currentstring .= $token->[2];
  932:     } elsif ($target eq 'tex') {
  933: 	$currentstring .= '}';
  934:     }
  935:     return $currentstring;
  936: }
  937: 
  938: #-- <i> tag (end tag required)
  939: sub start_i {
  940:     my ($target,$token) = @_;
  941:     my $currentstring = '';
  942:     if ($target eq 'web' || $target eq 'webgrade') {
  943: 	$currentstring .= $token->[4];
  944:     } elsif ($target eq 'tex') {
  945: 	$currentstring .= '\textit{';
  946:     }
  947:     return $currentstring;
  948: }
  949: 
  950: sub end_i {
  951:     my ($target,$token) = @_;
  952:     my $currentstring = '';
  953:     if ($target eq 'web' || $target eq 'webgrade') {
  954: 	$currentstring .= $token->[2];
  955:     } elsif ($target eq 'tex') {
  956: 	$currentstring .= '}';
  957:     } 
  958:     return $currentstring;
  959: }
  960: 
  961: #-- <address> tag (end tag required)
  962: sub start_address {
  963:     my ($target,$token) = @_;
  964:     my $currentstring = '';
  965:     if ($target eq 'web' || $target eq 'webgrade') {
  966: 	$currentstring .= $token->[4];
  967:     } elsif ($target eq 'tex') {
  968: 	$currentstring .= '\textit{';
  969:     }
  970:     return $currentstring;
  971: }
  972: 
  973: sub end_address {
  974:     my ($target,$token) = @_;
  975:     my $currentstring = '';
  976:     if ($target eq 'web' || $target eq 'webgrade') {
  977: 	$currentstring .= $token->[2];
  978:     } elsif ($target eq 'tex') {
  979: 	$currentstring .= '}';
  980:     }
  981:     return $currentstring;
  982: }
  983: 
  984: #-- <dfn> tag (end tag required)
  985: sub start_dfn {
  986:     my ($target,$token) = @_;
  987:     my $currentstring = '';
  988:     if ($target eq 'web' || $target eq 'webgrade') {
  989: 	$currentstring .= $token->[4];
  990:     } elsif ($target eq 'tex') {
  991: 	$currentstring .= '\textit{';
  992:     } 
  993:     return $currentstring;
  994: }
  995: 
  996: sub end_dfn {
  997:     my ($target,$token) = @_;
  998:     my $currentstring = '';
  999:     if ($target eq 'web' || $target eq 'webgrade') {
 1000: 	$currentstring .= $token->[2];
 1001:     } elsif ($target eq 'tex') {
 1002: 	$currentstring .= '}';
 1003:     }
 1004:     return $currentstring;
 1005: }
 1006: 
 1007: #-- <tt> tag (end tag required)
 1008: sub start_tt {
 1009:     my ($target,$token) = @_;
 1010:     my $currentstring = '';
 1011:     if ($target eq 'web' || $target eq 'webgrade') {
 1012: 	$currentstring .= $token->[4];
 1013:     } elsif ($target eq 'tex') {
 1014: 	$currentstring .= '\texttt{';
 1015:     }
 1016:     return $currentstring;
 1017: }
 1018: 
 1019: sub end_tt {
 1020:     my ($target,$token) = @_;
 1021:     my $currentstring = '';
 1022:     if ($target eq 'web' || $target eq 'webgrade') {
 1023: 	$currentstring .= $token->[2];
 1024:     } elsif ($target eq 'tex') {
 1025: 	$currentstring .= '}';
 1026:     }
 1027:     return $currentstring;
 1028: }
 1029: 
 1030: #-- <kbd> tag (end tag required)
 1031: sub start_kbd {
 1032:     my ($target,$token) = @_;
 1033:     my $currentstring = '';
 1034:     if ($target eq 'web' || $target eq 'webgrade') {
 1035: 	$currentstring .= $token->[4];
 1036:     } elsif ($target eq 'tex') {
 1037: 	$currentstring .= '\texttt{';
 1038:     }
 1039:     return $currentstring;
 1040: }
 1041: 
 1042: sub end_kbd {
 1043:     my ($target,$token) = @_;
 1044:     my $currentstring = '';
 1045:     if ($target eq 'web' || $target eq 'webgrade') {
 1046: 	$currentstring .= $token->[2];
 1047:     } elsif ($target eq 'tex') {
 1048: 	$currentstring .= '}';
 1049:     }
 1050:     return $currentstring;
 1051: }
 1052: 
 1053: #-- <code> tag (end tag required)
 1054: sub start_code {
 1055:     my ($target,$token) = @_;
 1056:     my $currentstring = '';
 1057:     if ($target eq 'web' || $target eq 'webgrade') {
 1058: 	$currentstring .= $token->[4];
 1059:     } elsif ($target eq 'tex') {
 1060: 	$currentstring .= '\texttt{';
 1061:     } 
 1062:     return $currentstring;
 1063: }
 1064: 
 1065: sub end_code {
 1066:     my ($target,$token) = @_;
 1067:     my $currentstring = '';
 1068:     if ($target eq 'web' || $target eq 'webgrade') {
 1069: 	$currentstring .= $token->[2];
 1070:     } elsif ($target eq 'tex') {
 1071: 	$currentstring .= '}';
 1072:     } 
 1073:     return $currentstring;
 1074: }
 1075: 
 1076: #-- <em> tag (end tag required)
 1077: sub start_em {
 1078:     my ($target,$token) = @_;
 1079:     my $currentstring = '';
 1080:     if ($target eq 'web' || $target eq 'webgrade') {
 1081: 	$currentstring .= $token->[4];
 1082:     } elsif ($target eq 'tex') {
 1083: 	$currentstring .= '\emph{';
 1084:     }
 1085:     return $currentstring;
 1086: }
 1087: 
 1088: sub end_em {
 1089:     my ($target,$token) = @_;
 1090:     my $currentstring = '';
 1091:     if ($target eq 'web' || $target eq 'webgrade') {
 1092: 	$currentstring .= $token->[2];
 1093:     } elsif ($target eq 'tex') {
 1094: 	$currentstring .= '}';
 1095:     } 
 1096:     return $currentstring;
 1097: }
 1098: 
 1099: #-- <q> tag (end tag required)
 1100: sub start_q {
 1101:     my ($target,$token) = @_;
 1102:     my $currentstring = '';
 1103:     if ($target eq 'web' || $target eq 'webgrade') {
 1104: 	$currentstring .= $token->[4];
 1105:     } elsif ($target eq 'tex') {
 1106: 	$currentstring .= '\emph{';
 1107:     }
 1108:     return $currentstring;
 1109: }
 1110: 
 1111: sub end_q {
 1112:     my ($target,$token) = @_;
 1113:     my $currentstring = '';
 1114:     if ($target eq 'web' || $target eq 'webgrade') {
 1115: 	$currentstring .= $token->[2];
 1116:     } elsif ($target eq 'tex') {
 1117: 	$currentstring .= '}';
 1118:     } 
 1119:     return $currentstring;
 1120: }
 1121: 
 1122: #  <p> is a bit strange since it does not require a closing </p>
 1123: #  However in latex, we must often output closing stuff to end
 1124: #  environments and {}'s etc.  Therefore we do all the work
 1125: #  of figuring out the ending strings in the start tag processing,
 1126: #  and provide a mechanism to output the stop text external
 1127: #  to tag processing.
 1128: #
 1129: {
 1130: 
 1131:     my $closing_string = '';		# String required to close <p>
 1132: 
 1133: #   Some tags are <p> fragile meaning that <p> inside of them
 1134: #   does not work within TeX mode.  This is managed via the 
 1135: #   counter below:
 1136: #
 1137: 
 1138:     my $para_disabled = 0;
 1139: 
 1140: sub disable_para {
 1141:     $para_disabled++;
 1142: }
 1143: sub enable_para {
 1144:     $para_disabled--;
 1145: }
 1146: 
 1147: 
 1148: #-- <p> tag (end tag optional)
 1149: #optional attribute - align="center|left|right"
 1150: sub start_p {
 1151:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 1152:     my $currentstring = '';
 1153:     if ($target eq 'web' || $target eq 'webgrade') {
 1154: 	$currentstring .= &end_p();	# close off prior para if in progress.
 1155: 	$currentstring .= $token->[4];
 1156: 	if (! ($currentstring =~ /\//)) {
 1157: 	    $closing_string = '</p>'; # Deal correctly with <p /> e.g.
 1158: 	}
 1159:     } elsif ($target eq 'tex' && !$para_disabled) {
 1160: 
 1161: 	$currentstring .= &end_p();	# close off prior para if in progress.
 1162: 	my $align=&Apache::lonxml::get_param('align',$parstack,$safeeval,undef,1);
 1163: 	if ($align eq 'center') {
 1164: 	    $currentstring .='\begin{center}\par ';
 1165: 	    $closing_string = '\end{center}';
 1166: 	    if (&is_inside_of($tagstack, "table")) {
 1167: 		$currentstring = &center_correction().$currentstring;
 1168: 	    }
 1169: 	} elsif ($align eq 'right') {
 1170: 	    $currentstring.="\n".'{\flushright ';
 1171: #	    $currentstring.='\makebox['.$env{'form.textwidth'}.']{\hfill\llap{';
 1172: 	    $closing_string= "}\n";
 1173: 	} elsif ($align eq 'left') {
 1174: 	    $currentstring.= "\n".'{\flushleft ';
 1175: #	    $currentstring.='\noindent\makebox['.$env{'form.textwidth'}.']{{';
 1176: 	    $closing_string = "}\n";
 1177: 	} else {
 1178:             $currentstring.='\par ';
 1179: 	    if (&is_inside_of($tagstack, 'table')) {
 1180: 		$closing_string = '\vskip 0pt'; # Seems to be consistent with <p> in tables.
 1181: 	    } else {
 1182: 		$closing_string = '\strut\\\\\strut ';
 1183: 	    }
 1184:         }
 1185: 
 1186:     }
 1187:     return $currentstring;
 1188: }
 1189: #
 1190: #  End paragraph processing just requires that we output the
 1191: #  closing string that was saved and blank it.
 1192: sub end_p {
 1193:     #  Note only 'tex' mode uses disable_para and enable_para
 1194:     #  so we don't need to know the target in the check below:
 1195: 
 1196:     if (!$para_disabled) {
 1197: 	my $current_string = $closing_string;
 1198: 	$closing_string = '';	# Not in a para anymore.
 1199: 	return $current_string;
 1200:     } else {
 1201: 	return '';
 1202:     }
 1203: 
 1204: }
 1205: }
 1206: #-- <br> tag (end tag forbidden)
 1207: sub start_br {
 1208:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
 1209:     my $currentstring = '';
 1210:     if ($target eq 'web' || $target eq 'webgrade') {
 1211: 	$currentstring .= $token->[4];
 1212:     } elsif ($target eq 'tex') {
 1213: 	my @tempo=@$tagstack;
 1214: 	my $signal=0;
 1215: 	#  Not going to factor this to is_inside_of since that would require
 1216:         #  multiple stack traversals.
 1217: 	#
 1218: 	for (my $i=$#tempo;$i>=0;$i--) {
 1219: 	    if (($tempo[$i] eq 'b') || ($tempo[$i] eq 'strong') ||
 1220:                 ($tempo[$i] eq 'ol') || ($tempo[$i] eq 'ul'))  {
 1221: 		$signal=1;
 1222: 	    }
 1223: 	    if (($tempo[$i] eq 'td') || ($tempo[$i] eq 'th')) {
 1224: 		$signal = 1;
 1225: 	    }
 1226: 	}
 1227: 	if ($signal eq 1) {
 1228: 	    $currentstring .= ' \vskip 0 mm ';
 1229: 	} elsif ($$tagstack[-2] ne 'sub' && $$tagstack[-2] ne 'sup') {
 1230: 	    $currentstring .= '\strut \\\\ \strut ';
 1231: 	} else {                   # Honor break in simple <sup></sup>
 1232: 	    $currentstring .= '}} \strut \\\\ \strut \ensuremath{^{'; 
 1233: 	}
 1234:     }
 1235:     return $currentstring;
 1236: }
 1237: 
 1238: sub end_br {
 1239:     my ($target,$token) = @_;
 1240:     my $currentstring = '';
 1241:     if ($target eq 'web' || $target eq 'webgrade') {
 1242: 	$currentstring .= $token->[2];
 1243:     }
 1244:     return $currentstring;
 1245: }
 1246: 
 1247: #-- <big> tag (end tag required)
 1248: sub start_big {
 1249:     my ($target,$token) = @_;
 1250:     my $currentstring = '';
 1251:     if ($target eq 'web' || $target eq 'webgrade') {
 1252: 	$currentstring .= $token->[4];
 1253:     } elsif ($target eq 'tex') {
 1254: 	$currentstring .= '{\large ';
 1255:     } 
 1256:     return $currentstring;
 1257: }
 1258: 
 1259: sub end_big {
 1260:     my ($target,$token) = @_;
 1261:     my $currentstring = '';
 1262:     if ($target eq 'web' || $target eq 'webgrade') {
 1263: 	$currentstring .= $token->[2];
 1264:     } elsif ($target eq 'tex') {
 1265: 	$currentstring .= '}';
 1266:     }
 1267:     return $currentstring;
 1268: }
 1269: 
 1270: #-- <small> tag (end tag required)
 1271: sub start_small {
 1272:     my ($target,$token) = @_;
 1273:     my $currentstring = '';
 1274:     if ($target eq 'web' || $target eq 'webgrade') {
 1275: 	$currentstring .= $token->[4];
 1276:     } elsif ($target eq 'tex') {
 1277: 	$currentstring .= '{\footnotesize ';
 1278:     }
 1279:     return $currentstring;
 1280: }
 1281: 
 1282: sub end_small {
 1283:     my ($target,$token) = @_;
 1284:     my $currentstring = '';
 1285:     if ($target eq 'web' || $target eq 'webgrade') {
 1286: 	$currentstring .= $token->[2];
 1287:     } elsif ($target eq 'tex') {
 1288: 	$currentstring .= '}';
 1289:     }
 1290:     return $currentstring;
 1291: }
 1292: 
 1293: #-- <basefont> tag (end tag forbidden)
 1294: sub start_basefont {
 1295:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
 1296:     my $currentstring = '';
 1297:     if ($target eq 'web' || $target eq 'webgrade') {
 1298: 	$currentstring = $token->[4];     
 1299:     } elsif ($target eq 'tex') {
 1300: 	my $basesize=&Apache::lonxml::get_param('TeXsize',$parstack,$safeeval);
 1301: 	if (defined $basesize) {
 1302: 	    $currentstring = '{\\'.$basesize.' ';
 1303: 	}
 1304:     }
 1305:     return $currentstring;
 1306: }
 1307: 
 1308: sub end_basefont {
 1309:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 1310:     my $currentstring = '';
 1311:     if ($target eq 'web' || $target eq 'webgrade') {
 1312: 	$currentstring = $token->[4];     
 1313:     } elsif ($target eq 'tex') {
 1314: 	my $basesize=&Apache::lonxml::get_param('TeXsize',$parstack,$safeeval);
 1315: 	if (defined $basesize) {
 1316: 	    $currentstring = '}';
 1317: 	}
 1318:     }
 1319:     return $currentstring;
 1320: }
 1321: 
 1322: #-- <font> tag (end tag required)
 1323: sub start_font {
 1324:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
 1325:     my $currentstring = '';
 1326:     if ($target eq 'web' || $target eq 'webgrade') {
 1327: 	my $face=&Apache::lonxml::get_param('face',$parstack,$safeeval);
 1328: 	if ($face!~/symbol/i) {
 1329: 	    if (($env{'browser.fontenhance'} eq 'on') || 
 1330: 		($env{'browser.blackwhite'} eq 'on')) { return ''; }
 1331: 	}
 1332: 	$currentstring = $token->[4];     
 1333:     }  elsif ($target eq 'tex') {
 1334: 	my $fontsize=&Apache::lonxml::get_param('TeXsize',$parstack,$safeeval);
 1335: 	if (defined $fontsize) {
 1336: 	    $currentstring = '{\\'.$fontsize.' ';
 1337: 	}
 1338:     }
 1339:     return $currentstring;
 1340: }
 1341: 
 1342: sub end_font {
 1343:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
 1344:     my $currentstring = '';
 1345:     if ($target eq 'web' || $target eq 'webgrade') {
 1346: 	$currentstring = $token->[2];    
 1347:     }  elsif ($target eq 'tex') {
 1348: 	my $fontsize=&Apache::lonxml::get_param('TeXsize',$parstack,$safeeval);
 1349: 	if (defined $fontsize) {
 1350: 	    $currentstring = '}';
 1351: 	}
 1352:     }
 1353:     return $currentstring;
 1354: }
 1355:  
 1356: #-- <strike> tag (end tag required)
 1357: sub start_strike {
 1358:     my ($target,$token) = @_;
 1359:     my $currentstring = '';
 1360:     if ($target eq 'web' || $target eq 'webgrade') {
 1361: 	$currentstring .= $token->[4];
 1362:     } elsif ($target eq 'tex') {
 1363: 	&Apache::lonxml::startredirection();
 1364:     } 
 1365:     return $currentstring;
 1366: }
 1367: 
 1368: sub end_strike {
 1369:     my ($target,$token) = @_;
 1370:     my $currentstring = '';
 1371:     if ($target eq 'web' || $target eq 'webgrade') {
 1372: 	$currentstring .= $token->[2];
 1373:     } elsif ($target eq 'tex') {
 1374: 	$currentstring=&Apache::lonxml::endredirection();
 1375: 	$currentstring=~s/(\S)(\s+)(\S)/$1\}$2\\underline\{$3/g; 
 1376: 	$currentstring=~s/^\s*(\S)/\\underline\{$1/; 
 1377: 	$currentstring=~s/(\S)\s*$/$1\}/;
 1378:     }
 1379:     return $currentstring;
 1380: }
 1381: 
 1382: #-- <s> tag (end tag required)
 1383: sub start_s {
 1384:     my ($target,$token) = @_;
 1385:     my $currentstring = '';
 1386:     if ($target eq 'web' || $target eq 'webgrade') {
 1387: 	$currentstring .= $token->[4];
 1388:     } elsif ($target eq 'tex') {
 1389: 	&Apache::lonxml::startredirection();
 1390:     } 
 1391:     return $currentstring;
 1392: }
 1393: 
 1394: sub end_s {
 1395:     my ($target,$token) = @_;
 1396:     my $currentstring = '';
 1397:     if ($target eq 'web' || $target eq 'webgrade') {
 1398: 	$currentstring .= $token->[2];
 1399:     } elsif ($target eq 'tex') {
 1400: 	$currentstring=&Apache::lonxml::endredirection();
 1401: 	$currentstring=~s/(\S)(\s+)(\S)/$1\}$2\\underline\{$3/g;
 1402: 	$currentstring=~s/^\s*(\S)/\\underline\{$1/;
 1403: 	$currentstring=~s/(\S)\s*$/$1\}/;	
 1404:     }
 1405:     return $currentstring;
 1406: }
 1407: 
 1408: #-- <sub> tag (end tag required)
 1409: sub start_sub {
 1410:     my ($target,$token) = @_;
 1411:     my $currentstring = '';
 1412:     if ($target eq 'web' || $target eq 'webgrade') {
 1413: 	$currentstring .= $token->[4];
 1414:     } elsif ($target eq 'tex') {
 1415: 	$currentstring .= '\ensuremath{_{';
 1416:     } 
 1417:     return $currentstring;
 1418: }
 1419: 
 1420: sub end_sub {
 1421:     my ($target,$token) = @_;
 1422:     my $currentstring = '';
 1423:     if ($target eq 'web' || $target eq 'webgrade') {
 1424: 	$currentstring .= $token->[2];
 1425:     } elsif ($target eq 'tex') {
 1426: 	$currentstring .= '}}';
 1427:     }
 1428:     return $currentstring;
 1429: }
 1430: 
 1431: #-- <sup> tag (end tag required)
 1432: sub start_sup {
 1433:     my ($target,$token) = @_;
 1434:     my $currentstring = '';
 1435:     if ($target eq 'web' || $target eq 'webgrade') {
 1436: 	$currentstring .= $token->[4];
 1437:     } elsif ($target eq 'tex') {
 1438: 	$currentstring .= '\ensuremath{^{';
 1439:     } 
 1440:     return $currentstring;
 1441: }
 1442: 
 1443: sub end_sup {
 1444:     my ($target,$token) = @_;
 1445:     my $currentstring = '';
 1446:     if ($target eq 'web' || $target eq 'webgrade') {
 1447: 	$currentstring .= $token->[2];
 1448:     } elsif ($target eq 'tex') {
 1449: 	$currentstring .= '}}';
 1450:     }
 1451:     return $currentstring;
 1452: }
 1453: 
 1454: #-- <hr> tag (end tag forbidden)
 1455: sub start_hr {
 1456:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 1457:     my $currentstring = &end_p();	# End enclosing para.
 1458:     if ($target eq 'web' || $target eq 'webgrade') {
 1459: 	$currentstring .= $token->[4];
 1460:     } elsif ($target eq 'tex') {
 1461: 	my $LaTeXwidth = &Apache::lonxml::get_param('TeXwidth',$parstack,$safeeval,undef,0);
 1462: 	if (defined $LaTeXwidth) {
 1463: 	    if ($LaTeXwidth=~/^%/) {
 1464: 		substr($LaTeXwidth,0,1)='';
 1465: 		$LaTeXwidth=($LaTeXwidth/100).'\textwidth';
 1466: 	    }
 1467: 	} else {
 1468: 	    $LaTeXwidth ='0.9\textwidth';
 1469: 	}
 1470: 	my ($pre,$post);
 1471: 	my $align=&Apache::lonxml::get_param('align',$parstack,$safeeval,undef,1);
 1472: 	if (($align eq 'center') || (not defined $align)) {
 1473: 	    $pre=''; $post='';
 1474: 	} elsif ($align eq 'left') {
 1475: 	    $pre='\rlap{'; $post='} \hfill';
 1476: 	} elsif ($align eq 'right') {
 1477: 	    $pre=' \hfill \llap{'; $post='}';
 1478: 	}
 1479: 	$currentstring .= ' \vskip 0 mm \noindent\makebox['.$LaTeXwidth.']{'.$pre.'\makebox['.
 1480:                                     $LaTeXwidth.'][b]{\hrulefill}'.$post.'}\vskip 0 mm ';
 1481:     } 
 1482:     return $currentstring;
 1483: }
 1484: 
 1485: sub end_hr {
 1486:     my ($target,$token) = @_;
 1487:     my $currentstring = '';
 1488:     if ($target eq 'web' || $target eq 'webgrade') {
 1489: 	$currentstring .= $token->[2];
 1490:     }
 1491:     return $currentstring;
 1492: }
 1493: 
 1494: #-- <div> tag (end tag required)
 1495: {
 1496: 
 1497: #  Since div can be nested, the stack below is used
 1498: #  in 'tex' mode to store the ending strings
 1499: #  for the div stack.
 1500: 
 1501:     my @div_end_stack;
 1502: 
 1503: sub start_div {
 1504:     my ($target,$token, $tagstack, $parstack, $parser, $safeeval) = @_;
 1505:     my $currentstring = &end_p();	# Close enclosing para.
 1506:     if ($target eq 'web' || $target eq 'webgrade') {
 1507: 	$currentstring .= $token->[4];
 1508:     } 
 1509:     if ($target eq 'tex') {
 1510: 	# 4 possible alignments: left, right, center, and -missing-.
 1511: 
 1512: 	my $endstring = '';
 1513: 
 1514: 	my $align = lc(&Apache::lonxml::get_param('align', $parstack,
 1515: 						  $safeeval, undef, 1));
 1516: 	if ($align eq 'center') {
 1517: 	    $currentstring .= '\begin{center}';
 1518: 	    $endstring      = '\end{center}';
 1519: 	    if (&is_inside_of($tagstack, "table")) {
 1520: 		$currentstring = &center_correction().$currentstring;
 1521: 	    }
 1522: 	}
 1523: 	elsif ($align eq 'right') {
 1524: 	    $currentstring .= '\begin{flushright}';
 1525: 	    $endstring     .= '\end{flushright}';
 1526: 	} elsif ($align eq 'left') {
 1527: 	    $currentstring .= '\begin{flushleft}';
 1528: 	    $endstring     = '\end{flushleft}';
 1529: 	} else {
 1530: 	
 1531: 	}
 1532: 	$currentstring .= "\n";   # For human readability.
 1533: 	$endstring       = "\n$endstring\n"; # For human readability
 1534: 	push(@div_end_stack, $endstring);
 1535:     }
 1536:     return $currentstring;
 1537: }
 1538: 
 1539: sub end_div {
 1540:     my ($target,$token) = @_;
 1541:     my $currentstring = '';
 1542:     if ($target eq 'web' || $target eq 'webgrade') {
 1543: 	$currentstring .= $token->[2];
 1544:     }
 1545:     if ($target eq 'tex') {
 1546: 	my $endstring = pop @div_end_stack;
 1547: 	$currentstring .= $endstring;
 1548:     }
 1549:     return $currentstring;
 1550: }
 1551: }
 1552: 
 1553: #-- <a> tag (end tag required)
 1554: sub start_a {
 1555:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 1556:     my $currentstring = '';
 1557:     if ($target eq 'web' || $target eq 'webgrade') {
 1558: 	my $href=&Apache::lonxml::get_param('href',$parstack,$safeeval,
 1559: 					    undef,1);
 1560: 	$currentstring=&Apache::lonenc::encrypt_ref($token,{'href'=>$href});
 1561:     } elsif ($target eq 'tex') {
 1562: 	my $a=&Apache::lonxml::get_param('href',$parstack,$safeeval,undef,1);
 1563: 	my $b=&Apache::lonxml::get_param('name',$parstack,$safeeval,undef,1);
 1564: 	if ($a=~/\S/) {
 1565: 	    $a=~s/([^\\])%/$1\\\%/g;
 1566: 	    $currentstring .= '\ref{URI: '.$a.'}';
 1567: 	} elsif ($b=~/\S/) {
 1568: 	    $currentstring .= '\ref{Anchor: '.$b.'}';
 1569: 	} else {
 1570: 	    $currentstring.='';
 1571: 	}
 1572:     }
 1573:     return $currentstring;
 1574: }
 1575: 
 1576: sub end_a {
 1577:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 1578:     my $currentstring = '';
 1579:     if ($target eq 'web' || $target eq 'webgrade') {
 1580: 	$currentstring .= $token->[2];
 1581:     }
 1582:     return $currentstring;
 1583: }
 1584: 
 1585: #-- <li> tag (end tag optional)
 1586: sub start_li {
 1587:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 1588:     my $currentstring = '';
 1589:     if ($target eq 'web' || $target eq 'webgrade') {
 1590: 	$currentstring = $token->[4];     
 1591:     } elsif ($target eq 'tex') {
 1592: 	my $type=&Apache::lonxml::get_param('type',$parstack,$safeeval,undef,0);
 1593: 	my $value=&Apache::lonxml::get_param('value',$parstack,$safeeval,undef,0);
 1594: 	#FIXME need to support types i and I 
 1595: 	if ($type=~/disc/) {
 1596: 	    $currentstring .= ' \item[$\bullet$] ';
 1597: 	} elsif ($type=~/circle/) {
 1598: 	    $currentstring .= ' \item[$\circ$] ';
 1599: 	} elsif ($type=~/square/) {
 1600: 	    $currentstring .= ' \item[$\diamond$] ';
 1601: 	} elsif ($type eq '1') {
 1602: 	    $currentstring .= ' \item['.($Apache::londefdef::list_index+1).'.]';
 1603: 	} elsif ($type eq 'A') {
 1604: 	    $currentstring .= ' \item['.('A'..'Z')[$Apache::londefdef::list_index].'.]';
 1605: 	} elsif ($type eq 'a') {
 1606: 	    $currentstring .= ' \item['.('a'..'z')[$Apache::londefdef::list_index].'.]';
 1607: 	} elsif ($value ne '') {
 1608: 	    $currentstring .= ' \item['.$value.'] ';
 1609: 	} else {
 1610: 	    $currentstring .= ' \item ';
 1611: 	}  
 1612: 	$Apache::londefdef::list_index++;
 1613:     }
 1614:     return $currentstring;
 1615: }
 1616: 
 1617: sub end_li {
 1618:     my ($target,$token) = @_;
 1619:     my $currentstring = &end_p();	# In case there's a <p> in the <li>
 1620:     if ($target eq 'web' || $target eq 'webgrade') {
 1621: 	$currentstring .= $token->[2];     
 1622:     } 
 1623:     return $currentstring;
 1624: }
 1625: 
 1626: #-- <u> tag (end tag required)
 1627: sub start_u {
 1628:     my ($target,$token) = @_;
 1629:     my $currentstring = '';
 1630:     if ($target eq 'web' || $target eq 'webgrade') {
 1631: 	$currentstring .= $token->[4];
 1632:     } elsif ($target eq 'tex') {
 1633: 	&Apache::lonxml::startredirection();
 1634:     } 
 1635:     return $currentstring;
 1636: }
 1637: 
 1638: sub end_u {
 1639:     my ($target,$token) = @_;
 1640:     my $currentstring = '';
 1641:     if ($target eq 'web' || $target eq 'webgrade') {
 1642: 	$currentstring .= $token->[2];
 1643:     } elsif ($target eq 'tex') {
 1644: 	$currentstring=&Apache::lonxml::endredirection();
 1645: 	$currentstring=~s/(\S)(\s+)(\S)/$1\}$2\\underline\{$3/g;
 1646: 	$currentstring=~s/^\s*(\S)/\\underline\{$1/;
 1647: 	$currentstring=~s/(\S)\s*$/$1\}/;		
 1648:     }
 1649:     return $currentstring;
 1650: }
 1651: 
 1652: #-- <ul> tag (end tag required)
 1653: sub start_ul {
 1654:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 1655:     my $currentstring = &end_p();	# Close off enclosing list.
 1656:     if ($target eq 'web' || $target eq 'webgrade') {
 1657: 	$currentstring .= $token->[4];     
 1658:     } elsif ($target eq 'tex') {
 1659: 	my $TeXtype=&Apache::lonxml::get_param('type',$parstack,$safeeval,undef,0);
 1660: 	$Apache::londefdef::list_index=0;
 1661: 	if ($TeXtype eq 'disc') {
 1662: 	    $currentstring .= '\renewcommand{\labelitemi}{$\bullet$}'.
 1663:                               '\renewcommand{\labelitemii}{$\bullet$}'. 
 1664:                               '\renewcommand{\labelitemiii}{$\bullet$}'.
 1665:                               '\renewcommand{\labelitemiv}{$\bullet$}';
 1666: 	} elsif ($TeXtype eq 'circle') {
 1667: 	    $currentstring .= '\renewcommand{\labelitemi}{$\circ$}'.
 1668:                               '\renewcommand{\labelitemii}{$\circ$}'. 
 1669:                               '\renewcommand{\labelitemiii}{$\circ$}'.
 1670:                               '\renewcommand{\labelitemiv}{$\circ$}';
 1671: 	} elsif ($TeXtype eq 'square') {
 1672: 	    $currentstring .= '\renewcommand{\labelitemi}{$\diamond$}'.
 1673:                               '\renewcommand{\labelitemii}{$\diamond$}'. 
 1674:                               '\renewcommand{\labelitemiii}{$\diamond$}'.
 1675:                               '\renewcommand{\labelitemiv}{$\diamond$}';
 1676: 	}
 1677: 	$currentstring .= '\strut \begin{itemize}';  
 1678:     } 
 1679:     return $currentstring;
 1680: }
 1681: 
 1682: sub end_ul {
 1683:     my ($target,$token) = @_;
 1684:     my $currentstring = '';
 1685:     if ($target eq 'web' || $target eq 'webgrade') {
 1686: 	$currentstring = $token->[2];     
 1687:     } elsif ($target eq 'tex') {
 1688: 	$currentstring = '\end{itemize} \renewcommand{\labelitemi}{$\bullet$}'.
 1689:                                '\renewcommand{\labelitemii}{$\bullet$}'. 
 1690:                                '\renewcommand{\labelitemiii}{$\bullet$}'.
 1691:                                '\renewcommand{\labelitemiv}{$\bullet$}\strut ';  
 1692:     } 
 1693:     return $currentstring;
 1694: }
 1695: 
 1696: #-- <menu> tag (end tag required)
 1697: sub start_menu {
 1698:     my ($target,$token) = @_;
 1699:     my $currentstring = '';
 1700:     if ($target eq 'web' || $target eq 'webgrade') {
 1701: 	$currentstring = $token->[4];     
 1702:     } elsif ($target eq 'tex') {
 1703: 	$currentstring = " \\begin{itemize} ";  
 1704:     } 
 1705:     return $currentstring;
 1706: }
 1707: 
 1708: sub end_menu {
 1709:     my ($target,$token) = @_;
 1710:     my $currentstring = '';
 1711:     if ($target eq 'web' || $target eq 'webgrade') {
 1712: 	$currentstring = $token->[2];     
 1713:     } elsif ($target eq 'tex') {
 1714: 	$currentstring = " \\end{itemize}";  
 1715:     } 
 1716:     return $currentstring;
 1717: }
 1718: 
 1719: #-- <dir> tag (end tag required)
 1720: sub start_dir {
 1721:     my ($target,$token) = @_;
 1722:     my $currentstring = &end_p();	# In case there's a <p> prior to the list.
 1723:     if ($target eq 'web' || $target eq 'webgrade') {
 1724: 	$currentstring .= $token->[4];     
 1725:     } elsif ($target eq 'tex') {
 1726: 	$currentstring .= " \\begin{itemize} ";  
 1727:     } 
 1728:     return $currentstring;
 1729: }
 1730: 
 1731: sub end_dir {
 1732:     my ($target,$token) = @_;
 1733:     my $currentstring = '';
 1734:     if ($target eq 'web' || $target eq 'webgrade') {
 1735: 	$currentstring = $token->[2];     
 1736:     } elsif ($target eq 'tex') {
 1737: 	$currentstring = " \\end{itemize}";  
 1738:     } 
 1739:     return $currentstring;
 1740: }
 1741: 
 1742: #-- <ol> tag (end tag required)
 1743: sub start_ol {
 1744:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 1745:     my $currentstring = &end_p();	# In case there's a <p> prior to the list.
 1746:     if ($target eq 'web' || $target eq 'webgrade') {
 1747: 	$currentstring .= $token->[4];     
 1748:     } elsif ($target eq 'tex') {
 1749: 	$Apache::londefdef::list_index=0;
 1750: 	my $type=&Apache::lonxml::get_param('type',$parstack,$safeeval,undef,0);
 1751: 	if ($type eq '1') {
 1752: 	    $currentstring .= '\renewcommand{\labelenumi}{\arabic{enumi}.}'.
 1753:                               '\renewcommand{\labelenumii}{\arabic{enumii}.}'. 
 1754:                               '\renewcommand{\labelenumiii}{\arabic{enumiii}.}'.
 1755:                               '\renewcommand{\labelenumiv}{\arabic{enumiv}.}';
 1756: 	} elsif ($type eq 'A') {
 1757: 	    $currentstring .= '\renewcommand{\labelenumi}{\Alph{enumi}.}'.
 1758:                               '\renewcommand{\labelenumii}{\Alph{enumii}.}'. 
 1759:                               '\renewcommand{\labelenumiii}{\Alph{enumiii}.}'.
 1760:                               '\renewcommand{\labelenumiv}{\Alph{enumiv}.}';
 1761: 	} elsif ($type eq 'a') {
 1762: 	    $currentstring .= '\renewcommand{\labelenumi}{\alph{enumi}.}'.
 1763:                               '\renewcommand{\labelenumii}{\alph{enumii}.}'.
 1764:                               '\renewcommand{\labelenumiii}{\alph{enumiii}.}'.
 1765:                               '\renewcommand{\labelenumiv}{\alph{enumiv}.}';
 1766: 	} elsif ($type eq 'i') {
 1767: 	    $currentstring .= '\renewcommand{\labelenumi}{\roman{enumi}.}'.
 1768:                               '\renewcommand{\labelenumii}{\roman{enumii}.}'.
 1769:                               '\renewcommand{\labelenumiii}{\roman{enumiii}.}'.
 1770:                               '\renewcommand{\labelenumiv}{\roman{enumiv}.}';
 1771: 	} elsif ($type eq 'I') {
 1772: 	    $currentstring .= '\renewcommand{\labelenumi}{\Roman{enumi}.}'.
 1773:                               '\renewcommand{\labelenumii}{\Roman{enumii}.}'.
 1774:                               '\renewcommand{\labelenumiii}{\Roman{enumiii}.}'.
 1775:                               '\renewcommand{\labelenumiv}{\Roman{enumiv}.}';
 1776: 	}
 1777: 	$currentstring .= '\strut \begin{enumerate}';  
 1778:     } 
 1779:     return $currentstring;
 1780: }
 1781: 
 1782: sub end_ol {
 1783:     my ($target,$token) = @_;
 1784:     my $currentstring = '';
 1785:     if ($target eq 'web' || $target eq 'webgrade') {
 1786: 	$currentstring = $token->[2];     
 1787:     } elsif ($target eq 'tex') {
 1788: 	$currentstring = '\end{enumerate}\renewcommand{\labelenumi}{\arabic{enumi}.}'.
 1789:                                         '\renewcommand{\labelenumii}{\arabic{enumii}.}'.
 1790:                                         '\renewcommand{\labelenumiii}{\arabic{enumiii}.}'.
 1791:                                         '\renewcommand{\labelenumiv}{\arabic{enumiv}.}\strut ';  
 1792:     } 
 1793:     return $currentstring;
 1794: }
 1795: 
 1796: #-- <dl> tag (end tag required)
 1797: sub start_dl {
 1798:     my ($target,$token) = @_;
 1799:     my $currentstring = &end_p();	# In case there's a <p> unclosed prior to the list.
 1800:     if ($target eq 'web' || $target eq 'webgrade') {
 1801: 	$currentstring .= $token->[4];     
 1802:     } elsif ($target eq 'tex') {
 1803: 	$currentstring .= '\begin{description}';
 1804: 	$Apache::londefdef::DL++;
 1805: 	push(@Apache::londefdef::description,[]);
 1806: 	$Apache::londefdef::DD[$Apache::londefdef::DL]=0;
 1807: 	$Apache::londefdef::DT[$Apache::londefdef::DL]=0;
 1808: 	$Apache::londefdef::seenDT[$Apache::londefdef::DL]=0;
 1809:     } 
 1810:     return $currentstring;
 1811: }
 1812: 
 1813: sub end_dl {
 1814:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 1815:     my $currentstring = '';
 1816:     if ($target eq 'web' || $target eq 'webgrade') {
 1817: 	$currentstring = $token->[2];     
 1818:     } elsif ($target eq 'tex') {
 1819: 	if ($Apache::londefdef::DT[-1]) { &end_dt(@_); }
 1820: 	if ($Apache::londefdef::DD[-1]) { &end_dd(@_); }
 1821: 	foreach my $element (@{$Apache::londefdef::description[-1]}) {
 1822: 	    $currentstring.=' '.$element.' ';
 1823: 	}
 1824: 	pop(@Apache::londefdef::description);
 1825: 	$currentstring.='\end{description}';  
 1826: 	delete($Apache::londefdef::DD[$Apache::londefdef::DL]);
 1827: 	delete($Apache::londefdef::DT[$Apache::londefdef::DL]);
 1828: 	delete($Apache::londefdef::seenDT[$Apache::londefdef::DL]);
 1829: 	$Apache::londefdef::DL--;
 1830:     } 
 1831:     return $currentstring;
 1832: }
 1833: 
 1834: #-- <dt> tag (end tag optional)
 1835: sub start_dt {
 1836:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 1837:     my $currentstring='';
 1838:     if ($target eq 'web' || $target eq 'webgrade') {
 1839: 	$currentstring = $token->[4];     
 1840:     } elsif ($target eq 'tex') {
 1841: 	if ($Apache::londefdef::DT[-1]) { &end_dt(@_); }
 1842: 	if ($Apache::londefdef::DD[-1]) { &end_dd(@_); }
 1843: 	&Apache::lonxml::startredirection();
 1844: 	$Apache::londefdef::DT[-1]++;
 1845: 	$Apache::londefdef::seenDT[-1]=1;
 1846:     } 
 1847:     return $currentstring;
 1848: }
 1849: 
 1850: sub end_dt {
 1851:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 1852:     my $currentstring = '';
 1853:     if ($target eq 'web' || $target eq 'webgrade') {
 1854: 	$currentstring = $token->[2];    
 1855:     } elsif ($target eq 'tex') {
 1856: 	if ($Apache::londefdef::DT[-1]) {
 1857: 	    my $data=&item_cleanup();
 1858: 	    push(@{$Apache::londefdef::description[-1]},'\item['.$data.'] \strut \vskip 0mm');
 1859: 	    $Apache::londefdef::DT[-1]--;
 1860: 	}
 1861:     } 
 1862:     return $currentstring;
 1863: }
 1864: 
 1865: sub item_cleanup {
 1866:     my $item=&Apache::lonxml::endredirection();
 1867:     $item=~s/\\begin{center}//g;
 1868:     $item=~s/\\end{center}//g;
 1869:     return $item;
 1870: }
 1871: 
 1872: #-- <dd> tag (end tag optional)
 1873: sub start_dd {
 1874:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 1875:     my $currentstring = '';
 1876:     if ($target eq 'web' || $target eq 'webgrade') {
 1877: 	$currentstring = $token->[4];     
 1878:     } elsif ($target eq 'tex') {
 1879: 	if ($Apache::londefdef::DT[-1]) { &end_dt(@_); }
 1880: 	if ($Apache::londefdef::DD[-1]) { &end_dd(@_);}
 1881: 	if (!$Apache::londefdef::seenDT[-1]) {
 1882: 	    push(@{$Apache::londefdef::description[-1]},'\item[\strut] \strut \vskip 0mm ');
 1883: 	}
 1884: 	push(@{$Apache::londefdef::description[-1]},'');
 1885: 	$Apache::londefdef::description[-1]->[-1].=' \strut ';
 1886: 	$Apache::londefdef::DD[-1]++;
 1887: 	&Apache::lonxml::startredirection();
 1888:     } 
 1889:     return $currentstring;
 1890: }
 1891: 
 1892: sub end_dd {
 1893:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 1894:     my $currentstring = '';
 1895:     if ($target eq 'web' || $target eq 'webgrade') {
 1896: 	$currentstring = $token->[2];    
 1897:     }  elsif ($target eq 'tex') {
 1898: 	$Apache::londefdef::description[-1]->[-1].=
 1899: 	    &Apache::lonxml::endredirection().' \vskip 0mm ';
 1900: 	$Apache::londefdef::DD[-1]--;
 1901:     }
 1902:     return $currentstring;
 1903: }
 1904: 
 1905: #-- <table> tag (end tag required)
 1906: #       <table> also ends any prior <p> that is not closed.
 1907: #               but, unless I allow <p>'s to nest, that's the
 1908: #               only way I could think of to allow <p> in 
 1909: #               <tr> <th> bodies
 1910: #
 1911: #list of supported attributes: border,width,TeXwidth
 1912: sub start_table {
 1913:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 1914:     my $textwidth = '';
 1915:     my $currentstring = &end_p();
 1916:     if ($target eq 'web' || $target eq 'webgrade') {
 1917: 	$currentstring .= $token->[4];     
 1918:     } elsif ($target eq 'tex') {
 1919: 	my $aa = {};
 1920: 	push @Apache::londefdef::table, $aa; 
 1921: 	$Apache::londefdef::table[-1]{'row_number'} = -1;
 1922:         #maximum table's width (default coincides with text line length)
 1923: 	if ($#Apache::londefdef::table==0) {
 1924: 	    $textwidth=&recalc($env{'form.textwidth'}); #result is always in mm
 1925: 	    $textwidth=~/(\d+\.?\d*)/;
 1926: 	    $textwidth=0.95*$1; #accounts "internal" LaTeX space for table frame
 1927: 	} else {
 1928: 	    if ($Apache::londefdef::table[-2]{'TeXlen'}[$Apache::londefdef::table[-2]{'row_number'}][$Apache::londefdef::table[-2]{'counter_columns'}]=~/\d/) {
 1929: 		#the maximum width of nested table is determined by LATeX width of parent cell
 1930: 		$textwidth=$Apache::londefdef::table[-2]{'TeXlen'}[$Apache::londefdef::table[-2]{'row_number'}][$Apache::londefdef::table[-2]{'counter_columns'}]; 
 1931: 	    } else {
 1932:               #try to use all space not used before (minus 5% for LaTeX table internal) - rather silly
 1933: 		$textwidth=$Apache::londefdef::table[-2]{'width'};
 1934: 		for (my $i=0;$i<$Apache::londefdef::table[-2]{'counter_columns'};$i++) {
 1935: 		    $textwidth=$textwidth-$Apache::londefdef::table[-2]{'TeXlen'}[0][$i];
 1936: 		}
 1937: 	    }
 1938: 	}
 1939: 
 1940: 	# width either comes forced from the TeXwidth or the width parameters.
 1941: 	# in either case it can be a percentage or absolute width.
 1942: 	# in the width case we ignore absolute width 
 1943: 	my $TeXwidth = &Apache::lonxml::get_param('TeXwidth',$parstack,$safeeval,undef,0);
 1944: 	if (!defined($TeXwidth)) {
 1945: 	    my $htmlwidth = &Apache::lonxml::get_param('width',$parstack,
 1946: 						       $safeeval,undef,1);
 1947: 	    if ($htmlwidth =~ /%/) {
 1948: 		$TeXwidth = $htmlwidth;
 1949: 	    } else { 
 1950: 		$TeXwidth = $textwidth;
 1951: 	    }
 1952: 	} else {
 1953: 	    $Apache::londefdef::table[-1]{'forcedtablewidth'} = 1;
 1954: 	}
 1955: 	if ($TeXwidth=~/%/) {
 1956: 	    $Apache::londefdef::table[-1]{'percent'}=1;
 1957: 	    $TeXwidth=~/(\d+)/;
 1958:             $Apache::londefdef::table[-1]{'width'}=$1*$textwidth/100;
 1959: 	} else {
 1960: 	    $Apache::londefdef::table[-1]{'width'}=$TeXwidth;
 1961: 	}
 1962:         #  In the end, however the table width cannot be wider than $textwidth...
 1963: 	
 1964: 	if ($Apache::londefdef::table[-1]{'width'} > $textwidth) {
 1965: 	    $Apache::londefdef::table[-1]{'width'} = $textwidth;
 1966: 	}
 1967: 
 1968:         #table's border
 1969: 	my $border = &Apache::lonxml::get_param('border',$parstack,$safeeval); 
 1970:         my $permission=&Apache::lonxml::get_param('TeXDropEmptyColumns',$parstack,$safeeval,undef,0);
 1971: 	unless (defined $border) { $border = 0; }
 1972: 	if ($border) { 
 1973: 	    $Apache::londefdef::table[-1]{'hinc'} = '\hline '; 
 1974: 	    $Apache::londefdef::table[-1]{'vinc'} = '&'; 
 1975: 	    $Apache::londefdef::table[-1]{'vvinc'} = '|';
 1976: 	} else {
 1977: 	    $Apache::londefdef::table[-1]{'hinc'} = ''; 
 1978: 	    $Apache::londefdef::table[-1]{'vinc'} = '&'; 
 1979: 	    $Apache::londefdef::table[-1]{'vvinc'} = '';
 1980: 	}
 1981: 	if ($#Apache::londefdef::table==0) {
 1982: 	    #    Note that \newline seems to destroy the alignment envs.
 1983: 	    # $Apache::londefdef::table[-1]{'output'}='\strut\newline\strut\setlength{\tabcolsep}{1 mm}';
 1984: 	    $Apache::londefdef::table[-1]{'output'}='\strut'.'\\\\'."\n".'\strut\setlength{\tabcolsep}{1 mm}';
 1985: 	}
 1986: 	$Apache::londefdef::table[-1]{'output'}.=' \noindent \begin{tabular} ';
 1987:         $Apache::londefdef::table[-1]{'TeXlen'}=[];
 1988:         $Apache::londefdef::table[-1]{'objectlen'}=[];
 1989:         $Apache::londefdef::table[-1]{'objectsignal'}=[];
 1990:         $Apache::londefdef::table[-1]{'maxlen'}=[];
 1991:         $Apache::londefdef::table[-1]{'minlen'}=[];
 1992:         $Apache::londefdef::table[-1]{'content'}=[];
 1993:         $Apache::londefdef::table[-1]{'align'}=[];
 1994:         $currentstring.='\keephidden{NEW TABLE ENTRY}';
 1995: 
 1996: 
 1997:     }
 1998:     return $currentstring;
 1999: }
 2000:  
 2001: sub end_table {
 2002:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 2003:     my $currentstring = '';
 2004:     if ($target eq 'web' || $target eq 'webgrade') {
 2005: 	$currentstring = $token->[2];     
 2006:     } elsif ($target eq 'tex') {
 2007: 	my $inmemory = '';
 2008: 	my $output = '';
 2009: 	my $WARNING='';
 2010:         #width of columns from TeXwidth attributes
 2011: 
 2012: 	for (my $in=0;$in<=$Apache::londefdef::table[-1]{'row_number'};$in++) {
 2013: 	    for (my $jn=0;$jn<=$Apache::londefdef::table[-1]{'counter_columns'};$jn++) {
 2014: 		if ($Apache::londefdef::table[-1]{'TeXlen'}[0][$jn]<$Apache::londefdef::table[-1]{'TeXlen'}[$in][$jn]) {
 2015: 		    $Apache::londefdef::table[-1]{'TeXlen'}[0][$jn]=$Apache::londefdef::table[-1]{'TeXlen'}[$in][$jn];
 2016: 		}	
 2017: 	    }
 2018: 	}
 2019:         #free space and number of empty columns
 2020: 	my ($available_space,$empty_columns)=($Apache::londefdef::table[-1]{'width'},0);
 2021: 	if ($#Apache::londefdef::table ne 0) {$available_space=0.9*$available_space;} 
 2022: 	for (my $jn=0;$jn<=$Apache::londefdef::table[-1]{'counter_columns'};$jn++) {
 2023: 	    if ($Apache::londefdef::table[-1]{'TeXlen'}[0][$jn]==0) {
 2024: 		$empty_columns++;
 2025: 	    } else {
 2026: 		$available_space=$available_space-$Apache::londefdef::table[-1]{'TeXlen'}[0][$jn];
 2027: 	    }
 2028: 	}
 2029:         #boundaries for contents columns
 2030: 	my @min_len=();#columns can not be narrower 
 2031: 	my @max_len=();#maximum length of column
 2032: 	for (my $jn=0;$jn<=$Apache::londefdef::table[-1]{'counter_columns'};$jn++) {
 2033: 		my ($localmin,$localmax)=(0,0);
 2034: 		for (my $in=0;$in<=$Apache::londefdef::table[-1]{'row_number'};$in++) {
 2035: 		    if ($localmin<$Apache::londefdef::table[-1]{'minlen'}[$in][$jn]) {
 2036: 			$localmin=$Apache::londefdef::table[-1]{'minlen'}[$in][$jn];
 2037: 		    }
 2038: 		    if ($localmax<$Apache::londefdef::table[-1]{'maxlen'}[$in][$jn]) {
 2039: 			$localmax=$Apache::londefdef::table[-1]{'maxlen'}[$in][$jn];
 2040: 		    }
 2041: 		}
 2042: 		push @min_len, $localmin;
 2043: 		push @max_len, $localmax;
 2044: 	}
 2045: 	for (my $jn=0;$jn<=$Apache::londefdef::table[-1]{'counter_columns'};$jn++) {
 2046: 	    my $localmin=0,;
 2047: 	    for (my $in=0;$in<=$Apache::londefdef::table[-1]{'row_number'};$in++) {
 2048: 		if ($localmin<$Apache::londefdef::table[-1]{'objectlen'}[$in][$jn]) {
 2049: 		    $localmin=$Apache::londefdef::table[-1]{'objectlen'}[$in][$jn];
 2050: 		}
 2051: 	    }
 2052: 	    if ($max_len[$jn]<$localmin) {
 2053: 		$max_len[$jn]=$localmin;
 2054: 	    	$Apache::londefdef::table[-1]{'objectsignal'}[$jn]=1;
 2055: 	    }#object size is bigger
 2056: 	    if ($min_len[$jn]<$localmin) {
 2057: 		$min_len[$jn]=$localmin;
 2058: 		$Apache::londefdef::table[-1]{'objectsignal'}[$jn]=1;
 2059: 	    }#object size is bigger
 2060: 	    if ($Apache::londefdef::table[-1]{'TeXlen'}[0][$jn]!=0) {
 2061: 		$min_len[$jn]=0;
 2062: 		$max_len[$jn]=0;
 2063: 	    }
 2064: 	}
 2065:        #final adjustment of column width
 2066: 	my @fwidth=@{$Apache::londefdef::table[-1]{'TeXlen'}[0]};#final width array
 2067: 	my @adjust=();
 2068:         #step 1. adjustment by maximum value
 2069: 	my $space_neeeded=0;
 2070: 	for (my $jn=0;$jn<=$#max_len;$jn++) {
 2071: 	    $space_neeeded=$space_neeeded+$max_len[$jn];
 2072: 	}
 2073: 	if ($space_neeeded<=$available_space) {
 2074: 	    for (my $jn=0;$jn<=$#max_len;$jn++) {
 2075: 		if ($fwidth[$jn]==0) {
 2076: 		    $fwidth[$jn]=$max_len[$jn];
 2077: 		}
 2078: 	    }
 2079: 	} else {
 2080:         #step 2. adjustment by minimum value (estimation)
 2081: 	    $space_neeeded=0;
 2082: 	    for (my $jn=0;$jn<=$#min_len;$jn++) {
 2083: 		$space_neeeded+=$min_len[$jn];
 2084: 	    }
 2085: 	    if ($space_neeeded>$available_space) {
 2086: 		$WARNING=' \textbf{NOT ENOUGH SPACE FOR TABLE} ';
 2087: 		for (my $jn=0;$jn<=$#max_len;$jn++) {
 2088: 		    if ($fwidth[$jn]==0) {
 2089: 			$fwidth[$jn]=$min_len[$jn];
 2090: 		    }
 2091: 		}
 2092: 		#check if we have objects which can be scaled
 2093: 		my $how_many_to_scale=0;
 2094: 		my @to_scale=();
 2095: 		for (my $jn=0;$jn<=$#max_len;$jn++) {
 2096: 		    if ($Apache::londefdef::table[-1]{'objectsignal'}[$jn] eq '1') {
 2097: 			$how_many_to_scale++;
 2098: 			push @to_scale, $jn;
 2099: 		    }
 2100: 		}
 2101: 		if ($how_many_to_scale>0) {
 2102: 		    my $space_to_adjust=($space_neeeded-$available_space)/$how_many_to_scale;
 2103: 		    foreach my $jn (@to_scale) {
 2104: 			for (my $in=0;$in<=$Apache::londefdef::table[-1]{'row_number'};$in++) {
 2105: 			    $Apache::londefdef::table[-1]{'content'}[$in][$jn]=~m/width\s*=\s*(\d+\.?\d*\s*(mm|cm|in|pc|pt)*)/;
 2106: 			    if ($1 ne '') {
 2107: 				my $current_length=&recalc($1);
 2108: 				$current_length=~/(\d+\.?\d*)/;
 2109: 				$current_length=$current_length-$space_to_adjust;
 2110: 				$Apache::londefdef::table[-1]{'content'}[$in][$jn]=~s/width\s*=\s*(\d+\.?\d*\s*(mm|cm|in|pc|pt)*)/width=$current_length mm/;
 2111: 			    }
 2112: 			    $Apache::londefdef::table[-1]{'content'}[$in][$jn]=~m/\[(\d+\.?\d*)\s*mm\]/;
 2113: 			    if ($1 ne '') {
 2114: 				my $current_length=$1;
 2115: 				$current_length=$current_length-$space_to_adjust;
 2116: 				$Apache::londefdef::table[-1]{'content'}[$in][$jn]=~s/\[(\d+\.?\d*)\s*mm\]/\[$current_length mm\]/;
 2117: 			    }				
 2118: 			}
 2119: 			$fwidth[$jn]=$fwidth[$jn]-$space_to_adjust;
 2120: 		    }
 2121: 		}
 2122: 	    } else {
 2123: 	      #step 3. adjustment over minimal + corrections
 2124: 		my $enlarge_coef=$available_space/$space_neeeded;
 2125: 		my $acsessive=0;
 2126: 		for (my $jn=0;$jn<=$#min_len;$jn++) {
 2127: 		    $adjust[$jn]=$min_len[$jn]*$enlarge_coef;
 2128: 		    if ($adjust[$jn]>$max_len[$jn]) {
 2129: 			$fwidth[$jn]=$max_len[$jn];
 2130: 			$acsessive=$acsessive+$adjust[$jn]-$max_len[$jn];
 2131: 			$adjust[$jn]=0;
 2132: 		    }
 2133: 		}
 2134: 		if ($acsessive>0) {
 2135: 		#we have an excess of space and can redistribute it
 2136: 		    my $notempty_columns=0;
 2137: 		    for (my $jn=0;$jn<=$#min_len;$jn++) {
 2138: 			if ($adjust[$jn]!=0) {
 2139: 			    $notempty_columns++;
 2140: 			}
 2141: 		    }
 2142: 		    my $per_column=$acsessive/$notempty_columns;
 2143: 		    for (my $jn=0;$jn<=$#min_len;$jn++) {
 2144: 			if ($adjust[$jn]!=0) {
 2145: 			    $adjust[$jn]+=$per_column;
 2146: 			    $fwidth[$jn]=$adjust[$jn];
 2147: 			}
 2148: 		    }
 2149: 		} else {
 2150: 		    for (my $jn=0;$jn<=$#min_len;$jn++) {
 2151: 			$fwidth[$jn]=$adjust[$jn];
 2152: 		    }
 2153: 		}
 2154: 	    }
 2155: 	}
 2156:         #use all available width if it is defined in % or as TeXwidth
 2157:         if (($Apache::londefdef::table[-1]{'percent'}==1) || ($Apache::londefdef::table[-1]{'forcetablewidth'}==1)) {
 2158: 	    my $current=0; 
 2159: 	    for (my $i=0;$i<=$#fwidth;$i++) {  
 2160: 		$current+=$fwidth[$i];
 2161: 	    }
 2162: 	    my $coef=$Apache::londefdef::table[-1]{'width'}/$current;
 2163: 	    for (my $i=0;$i<=$#fwidth;$i++) {  
 2164: 		$fwidth[$i]*=$coef;
 2165: 	    }
 2166: 	}
 2167:         #removing of empty columns if allowed
 2168:         my $permission=&Apache::lonxml::get_param('TeXDropEmptyColumns',$parstack,$safeeval,undef,0);
 2169: 	if ($permission eq 'yes') {
 2170: 	    my @cleaned_table=();
 2171:             my @cleaned_header=();
 2172: 	    my $colind=0;
 2173: 	    for (my $jn=0;$jn<=$Apache::londefdef::table[-1]{'counter_columns'};$jn++) {
 2174: 		if ($fwidth[$jn]!=0) {
 2175: 		    #we need to copy column
 2176: 		    for (my $in=0;$in<=$Apache::londefdef::table[-1]{'row_number'};$in++) {
 2177: 			$cleaned_table[$in][$colind]=$Apache::londefdef::table[-1]{'content'}[$in][$jn];
 2178: 			$cleaned_header[$colind]=$fwidth[$jn];
 2179: 		    }
 2180: 		    $colind++;
 2181: 		}
 2182: 	    }
 2183: 	    $Apache::londefdef::table[-1]{'content'}=\@cleaned_table;
 2184: 	    @fwidth=@cleaned_header;
 2185: 	}
 2186: 	#construct header of the table
 2187: 	my $header_of_table = '{'.$Apache::londefdef::table[-1]{'vvinc'};
 2188: 	for (my $in=0;$in<=$#fwidth;$in++) {
 2189: 	    $header_of_table.='p{'.$fwidth[$in].' mm}'.$Apache::londefdef::table[-1]{'vvinc'};
 2190: 	}
 2191: 	$header_of_table .= '}';
 2192: 	#fill the table
 2193: 	for (my $in=0;$in<=$Apache::londefdef::table[-1]{'row_number'};$in++) {
 2194: 	    my $have_rowspan = 0;
 2195: 	    for (my $jn=0;$jn<=$#fwidth;$jn++) {
 2196: 
 2197: 		#-----------------------------------------------------------
 2198:                 #   I think this order of doing things will ensure that
 2199: 		#   single rowspan, columspan and combined row/colspans will
 2200:                 #   work correctly.  LaTeX is delicate here.
 2201: 		#    RF.
 2202: 
 2203: 		# Start a rowspan if necessary:
 2204: 
 2205: 		my $rowspan = $Apache::londefdef::table[-1]{'rowspan'}[$in][$jn];
 2206: 		my $colspan = $Apache::londefdef::table[-1]{'colspan'}[$in][$jn];
 2207: 		#
 2208: 		#  Do the appropriate magic if this has a colspan
 2209: 		# 
 2210: 
 2211: 		if ($colspan > 1) {
 2212: 		    my $spanwidth = 0;
 2213: 		    for (my $spancol = $jn; $spancol < $jn + $colspan; $spancol++) {
 2214: 			$spanwidth += $fwidth[$spancol];
 2215: 		    }
 2216: 		    $output .= '\multicolumn{'.
 2217: 			$colspan
 2218: 			."}";
 2219: 		    if ($Apache::londefdef::table[-1]{'align'}[$in][$jn] eq 'c') {
 2220: 			$output .= '{|c|}{';
 2221: 		    } elsif ($Apache::londefdef::table[-1]{'align'}[$in][$jn] eq 'r') {
 2222: 			$output .= '{|r|}{';
 2223: 		    }
 2224: 		    else {
 2225: 			$output .= "{|p{$spanwidth mm}|}{";
 2226: 		    }
 2227: 			
 2228: 		}
 2229: 
 2230: 		# Rowspan... if colspan is 1, and there's an alignment we'll need
 2231: 		# to kick in a multicolumn in order to get the alignment spec.
 2232: 		# this must precede the multirow or LaTex gets quite upset.
 2233: 		# Naturally if colspan > 1 we've already done that above ^
 2234: 		#
 2235: 		my $multirow_aligned = 0;
 2236: 		if ($rowspan > 1) {
 2237: 		    if ($colspan == 1) {
 2238: 			if ($Apache::londefdef::table[-1]{'align'}[$in][$jn] eq 'c') {
 2239: 			    $output .= '\multicolumn{1}{|c|}{';
 2240: 			    $multirow_aligned = 1;
 2241: 			} elsif ($Apache::londefdef::table[-1]{'align'}[$in][$jn] eq 'r') {
 2242: 			    $output .= '\multicolumn{1}{|r|}{';
 2243: 			    $multirow_aligned = 1;
 2244: 			}
 2245: 		    }
 2246: 		    $have_rowspan++;
 2247: 		    $output .= '\multirow{'.$rowspan.'}[0]{*}{';
 2248: 		    #
 2249: 		    # If we did not throw in a multicolumn to align, then add 
 2250: 		    # an extra {
 2251: 		    # so we close correctly without having to keep additional state
 2252: 		    # around
 2253: 		    #
 2254: 		    if (!$multirow_aligned) {
 2255: 			$output .= '{';
 2256: 		    }
 2257: 		}
 2258: 		if (($rowspan eq '^') || ($rowspan eq '_')) {
 2259: 		    $have_rowspan++;
 2260: 		}
 2261: 		#--------------------------------------------------------------
 2262: 
 2263: 
 2264: 		# For right and center alignment of single cells.
 2265: 		# we are going to use a multicolumn with a span of 1 to specify alignment.
 2266: 		#
 2267: 		if ($colspan == 1  && $rowspan == 1) {
 2268: 		    if ($Apache::londefdef::table[-1]{'align'}[$in][$jn] eq 'c') {
 2269: 			$output .= '\multicolumn{1}{|c|}{';
 2270: 		    } elsif ($Apache::londefdef::table[-1]{'align'}[$in][$jn] eq 'r') {
 2271: 			$output .= '\multicolumn{1}{|r|}{';
 2272: 		    }
 2273: 		}
 2274: 
 2275: 		$output.=$Apache::londefdef::table[-1]{'content'}[$in][$jn];
 2276: 
 2277: 		if (($colspan == 1 && $rowspan == 1)   &&
 2278: 		    (($Apache::londefdef::table[-1]{'align'}[$in][$jn] eq 'c') ||
 2279: 		     ($Apache::londefdef::table[-1]{'align'}[$in][$jn] eq 'r'))) {
 2280: 		    $output .= '}';
 2281: 		}
 2282: 
 2283: 		# Close off any open multirow:
 2284: 		
 2285: 		if ($rowspan > 1) {
 2286: 		    $output .= '}}';
 2287: 		}
 2288: 		#  Close off the colspan...
 2289: 		#
 2290: 		if ($colspan > 1)  {
 2291: 		    $output .= '}';
 2292: 		    $jn += $colspan-1; # Adjust for number of rows really left.
 2293: 		}
 2294:                 if ($jn!=$#fwidth) {$output.=' '.$Apache::londefdef::table[-1]{'vinc'};}
 2295: 	    }
 2296: 	    #  If have_rowspan > 0, and borders are on, then 
 2297: 	    #  we need to do more than put an \hline at the bottom of row.
 2298: 	    #  we need to do the appropriate \cline to ensure that
 2299: 	    #  the spanned rows don't have \hlines through them.
 2300: 
 2301: 	    if (($Apache::londefdef::table[-1]{'hinc'} =~ /\\hline/) && $have_rowspan) {
 2302: 		$output .= ' \\\\ ';
 2303: 		for (my $jn=0; $jn<=$#fwidth;$jn++) {
 2304: 		    my $rowspan = $Apache::londefdef::table[-1]{'rowspan'}[$in][$jn];
 2305: 		    if ($rowspan ne "^") {
 2306: 			if (($rowspan <= 1) || ($rowspan eq '_')) {
 2307: 			    my $column = $jn+1;
 2308: 			    $output .= '\cline{'.$column.'-'.$column.'} ';
 2309: 			}
 2310: 		    }
 2311: 		}
 2312: 
 2313: 	    } else {
 2314: 		$output.=' \\\\ '.$Apache::londefdef::table[-1]{'hinc'}.' ';
 2315: 	    }
 2316: 	}
 2317: 	# Note that \newline destroys alignment env's produced  by e.g. <div>
 2318: 	# $Apache::londefdef::table[-1]{'output'} .= $header_of_table.$Apache::londefdef::table[-1]{'hinc'}.$output.'\end{tabular}\strut\newline\strut ';
 2319: 	$Apache::londefdef::table[-1]{'output'} .= $header_of_table.$Apache::londefdef::table[-1]{'hinc'}.$output.'\end{tabular}\strut'.'\\\\'."\n".'\strut ';
 2320: 	if ($#Apache::londefdef::table > 0) {	    
 2321: 	    my $inmemory = $Apache::londefdef::table[-1]{'output'};
 2322: 	    # Figure out max/and min width  by summing us and then
 2323: 	    # apply that to the current column of the table we nest in
 2324: 	    # if it's larger than the current width or the current width
 2325: 	    # is undefined.
 2326: 	    #
 2327: 	    my $min_nested_width = 0;
 2328: 	    my $max_nested_width = 0;
 2329: 	    for (my $col = 0; $col <= $Apache::londefdef::table[-1]{'counter_columns'}; $col++) {
 2330: 		$min_nested_width +=  $min_len[$col];
 2331: 		$max_nested_width +=  $max_len[$col];
 2332: 		
 2333: 	    }
 2334: 	    # Fudge in an extra 5 mm for borders etc:
 2335: 	    
 2336: 	    $min_nested_width += 5;
 2337: 	    $max_nested_width += 5;
 2338: 
 2339: 	    my $outer_column = $Apache::londefdef::table[-2]{'counter_columns'};
 2340: 	    my $outer_row    = $Apache::londefdef::table[-2]{'row_number'};
 2341: 	    if ($min_nested_width > $Apache::londefdef::table[-2]{'minlen'}[$outer_row][$outer_column]) {
 2342: 		$Apache::londefdef::table[-2]{'minlen'}[$outer_row][$outer_column] = $min_nested_width;
 2343: 	    }
 2344: 	    if ($max_nested_width > $Apache::londefdef::table[-2]{'maxlen'}[$outer_row][$outer_column]) {
 2345: 		$Apache::londefdef::table[-2]{'maxlen'}[$outer_row][$outer_column] = $max_nested_width;
 2346: 	    }
 2347: 
 2348: 	    pop @Apache::londefdef::table;
 2349: 	    push @{$Apache::londefdef::table[-1]{'include'}}, $inmemory;
 2350: 	} else {
 2351: 	    $currentstring .= $Apache::londefdef::table[-1]{'output'};
 2352: 	    pop @Apache::londefdef::table;
 2353: 	    undef @Apache::londefdef::table;
 2354: 	}
 2355:     }
 2356:     return $currentstring;
 2357: }
 2358: 
 2359: #-- <tr> tag (end tag optional)
 2360: sub start_tr {
 2361:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 2362:     my $currentstring = '';
 2363:     if ($target eq 'web' || $target eq 'webgrade') {
 2364: 	$currentstring = $token->[4];     
 2365:     } elsif ($target eq 'tex') {
 2366: 	$Apache::londefdef::table[-1]{'row_number'}++;
 2367: 	my $alignchar=&Apache::lonxml::get_param('align',$parstack,$safeeval,undef,1);
 2368: 	if ($alignchar ne '') {
 2369: 	    push @ {$Apache::londefdef::table[-1]{'rows'} },substr($alignchar,0,1);
 2370: 	} else {
 2371: 	    push @ {$Apache::londefdef::table[-1]{'rows'} }, 'l';
 2372: 	}
 2373: 	push ( @{ $Apache::londefdef::table[-1]{'rowdata'} }, $Apache::londefdef::table[-1]{'hinc'});
 2374: 	#
 2375: 	#  Need to save the number of table columns to preserve the max # columns.
 2376: 	#
 2377: 	$Apache::londefdef::table[-1]{'prior_columns'}   = $Apache::londefdef::table[-1]{'counter_columns'};
 2378: 	$Apache::londefdef::table[-1]{'counter_columns'} = -1;
 2379: 	push @ {$Apache::londefdef::table[-1]{'TeXlen'}}, [];
 2380: 	push @ {$Apache::londefdef::table[-1]{'objectlen'}}, [];
 2381: 	push @ {$Apache::londefdef::table[-1]{'minlen'}}, [];
 2382: 	push @ {$Apache::londefdef::table[-1]{'maxlen'}}, [];
 2383: 	push @ {$Apache::londefdef::table[-1]{'content'}}, [];
 2384:     } 
 2385:     return $currentstring;
 2386: }
 2387:         
 2388: sub end_tr {
 2389:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 2390:     my $currentstring = &end_p();	# Close any pending <p> in the row.
 2391:     if ($target eq 'web' || $target eq 'webgrade') {
 2392: 	$currentstring .= $token->[2];     
 2393:     } elsif ($target eq 'tex') {
 2394: 	if ($Apache::londefdef::TD_redirection) {
 2395: 	    &end_td_tex($parstack,$parser,$safeeval);    
 2396: 	}
 2397: 	# Counter columns must be the maximum number of columns seen
 2398: 	# in the table so far so:
 2399: 	if ($Apache::londefdef::table[-1]{'prior_columns'} > $Apache::londefdef::table[-1]{'counter_columns'}) {
 2400: 	    $Apache::londefdef::table[-1]{'counter_columns'} = $Apache::londefdef::table[-1]{'prior_columns'};
 2401: 	}
 2402: 
 2403: 
 2404: 	
 2405:     }
 2406:     return $currentstring;
 2407: }
 2408: 
 2409: #-- <td> tag (end tag optional)
 2410: sub start_td {
 2411:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 2412:     my $currentstring = '';
 2413:     if ($target eq 'web' || $target eq 'webgrade') {
 2414: 	$currentstring = $token->[4];     
 2415:     } elsif ($target eq 'tex') {
 2416: 	$Apache::londefdef::TD_redirection = 1;
 2417: 	&tag_check('tr','td',$tagstack,$parstack,$parser,$safeeval);
 2418:     } 
 2419:     return $currentstring;
 2420: }   
 2421:     
 2422: sub tag_check {
 2423:     my ($good_tag,$bad_tag,$tagstack,$parstack,$parser,$safeeval) = @_;
 2424:     my @ar=@$parstack; 
 2425:     for (my $i=$#ar-1;$i>=0;$i--) {
 2426: 	if (lc($$tagstack[$i]) eq $good_tag) {
 2427: 	    &start_td_tex($parstack,$parser,$safeeval);
 2428: 	    last;
 2429: 	} elsif (lc($$tagstack[$i]) eq $bad_tag) {
 2430: 	    splice @ar, $i+1;
 2431: 	    &end_td_tex(\@ar,$parser,$safeeval);
 2432: 	    &start_td_tex($parstack,$parser,$safeeval);
 2433: 	    last;
 2434: 	}
 2435:     }
 2436:     return '';
 2437: }
 2438:  
 2439: sub start_td_tex {
 2440:     my ($parstack,$parser,$safeeval) = @_;
 2441:     my $alignchar = substr(&Apache::lonxml::get_param('align',$parstack,$safeeval,undef,1),0,1);
 2442:     if ($alignchar eq '') {
 2443: 	$alignchar = $Apache::londefdef::table[-1]{'rows'}[-1];
 2444:     }
 2445:     push @{ $Apache::londefdef::table[-1]{'align'}[$Apache::londefdef::table[-1]{'row_number'}] }, $alignchar;
 2446:     $Apache::londefdef::table[-1]{'counter_columns'}++;
 2447:     my $TeXwidth=&Apache::lonxml::get_param('TeXwidth',$parstack,$safeeval,undef,0);
 2448:     if (defined $TeXwidth) {		
 2449: 	my $current_length=&recalc($TeXwidth);
 2450: 	$current_length=~/(\d+\.?\d*)/;
 2451: 	push @ {$Apache::londefdef::table[-1]{'TeXlen'}[$Apache::londefdef::table[-1]{'row_number'}] },$1;
 2452:     }
 2453:     &Apache::lonxml::startredirection();
 2454:     return '';
 2455: }
 2456: 
 2457: sub end_td_tex {
 2458:     my ($parstack,$parser,$safeeval) = @_;
 2459:     my $current_row    = $Apache::londefdef::table[-1]{'row_number'};
 2460:     my $current_column = $Apache::londefdef::table[-1]{'counter_columns'}; 
 2461:     my $data = &Apache::lonxml::endredirection();
 2462: 
 2463:     #  The rowspan array of the table indicates which cells are part of a span.
 2464:     #  n indicates the start of a span set of n rows.
 2465:     #  ^ indicates a cell that continues a span set.
 2466:     #  _ indicates the cell is at the bottom of a span set.
 2467:     #  If this and subsequent cells are part of a rowspan, we must
 2468:     #  push along the row until we find one that is not.
 2469: 
 2470:     while ((defined $Apache::londefdef::table[-1]{'rowspan'}[$current_row] [$current_column]) 
 2471: 	   && ($Apache::londefdef::table[-1]{'rowspan'}[$current_row][$current_column] =~ /[\^\_]/)) {
 2472: 	# Part of a span.
 2473: 	push @ {$Apache::londefdef::table[-1]{'content'}[-1]}, '';
 2474: 	$current_column++;
 2475:     }
 2476:     $Apache::londefdef::table[-1]{'counter_columns'} = $current_column;
 2477:    
 2478: 
 2479:     # Get the column and row spans.
 2480:     # Colspan can be done via \multicolumn if I can figure out the data structs.
 2481: 
 2482:     my $colspan = &Apache::lonxml::get_param('colspan', $parstack, $safeeval, undef, 0);
 2483:     if (!$colspan) {
 2484: 	$colspan = 1;
 2485:     }
 2486: 
 2487:     my $rowspan = &Apache::lonxml::get_param('rowspan', $parstack, $safeeval, undef, 0);
 2488:     if (!$rowspan) {
 2489: 	$rowspan = 1;
 2490:     }
 2491: 
 2492: 
 2493: 
 2494:     for (my $c = 0; $c < $colspan; $c++) {
 2495: 	$Apache::londefdef::table[-1]{'rowspan'}[$current_row][$current_column+$c] = $rowspan;
 2496: 	for (my $i = 1; $i < $rowspan; $i++) {
 2497: 	    $Apache::londefdef::table[-1]{'rowspan'}[$current_row+$i][$current_column+$c] = '^';
 2498: 	    if ($i == ($rowspan-1)) {
 2499: 		$Apache::londefdef::table[-1]{'rowspan'}[$current_row+$i][$current_column+$c] = '_';
 2500: 	    }
 2501: 	}
 2502:     }
 2503: 
 2504:     my $TeXwidth=&Apache::lonxml::get_param('TeXwidth',$parstack,$safeeval,undef,0);
 2505:     if (defined $TeXwidth) {		
 2506: 	push @ {$Apache::londefdef::table[-1]{'objectlen'}[$Apache::londefdef::table[-1]{'row_number'}] },'0';
 2507: 	push @ {$Apache::londefdef::table[-1]{'minlen'}[$Apache::londefdef::table[-1]{'row_number'}] },'0';
 2508: 	push @ {$Apache::londefdef::table[-1]{'maxlen'}[$Apache::londefdef::table[-1]{'row_number'}] },'0';
 2509:     } else {
 2510: 	if (($data=~m/width\s*=\s*(\d+\.?\d*\s*(mm|cm|in|pc|pt)*)/) or ($data=~m/\[(\d+\.?\d*)\s*mm\]/)) {
 2511: 	    my $garbage_data=$data;
 2512: 	    my $fwidth=0;
 2513:             while ($garbage_data=~m/width\s*=\s*(\d+\.?\d*\s*(mm|cm|in|pc|pt)*)/) {
 2514: 		my $current_length=&recalc($1);
 2515: 		$current_length=~/(\d+\.?\d*)/;
 2516: 		if ($fwidth<$1) {$fwidth=$1;}
 2517: 		$garbage_data=~s/width\s*=\s*(\d+\.?\d*\s*(mm|cm|in|pc|pt)*)//;
 2518: 	    }
 2519:             while ($garbage_data=~m/\[(\d+\.?\d*)\s*mm\]/) {
 2520: 		my $current_length=$1;
 2521: 		if ($fwidth<$current_length) {$fwidth=$current_length;}
 2522: 		$garbage_data=~s/\[(\d+\.?\d*)\s*mm\]//;
 2523: 	    }
 2524: 	    push @ {$Apache::londefdef::table[-1]{'TeXlen'}[$Apache::londefdef::table[-1]{'row_number'}] },'0';
 2525: 	    push @ {$Apache::londefdef::table[-1]{'objectlen'}[$Apache::londefdef::table[-1]{'row_number'}] },$fwidth;
 2526: 	    push @ {$Apache::londefdef::table[-1]{'minlen'}[$Apache::londefdef::table[-1]{'row_number'}] },'0';
 2527: 	    push @ {$Apache::londefdef::table[-1]{'maxlen'}[$Apache::londefdef::table[-1]{'row_number'}] },'0';
 2528: 	} elsif ($data=~/\\parbox\{\s*\d+\.?\d*\s*(mm|cm|in|pc|pt)*\s*\}/ or $data=~/\\epsfxsize\s*=\s*\d+\.?\d*\s*(mm|cm|in|pc|pt)*/) {
 2529: 	    my $garbage_data=$data;
 2530: 	    my $fwidth=0;
 2531:             while ($garbage_data=~/\\parbox\{\s*(\d+\.?\d*\s*(mm|cm|in|pc|pt)*)\s*\}/) {
 2532: 		my $current_length=&recalc($1);
 2533: 		$current_length=~/(\d+\.?\d*)/;
 2534: 		if ($fwidth<$1) {$fwidth=$1;}
 2535: 		$garbage_data=~s/\\parbox\{\s*(\d+\.?\d*\s*(mm|cm|in|pc|pt)*)//;
 2536: 	    }
 2537:             while ($garbage_data=~/\\epsfxsize\s*=\s*(\d+\.?\d*\s*(mm|cm|in|pc|pt)*)/) {
 2538: 		my $current_length=&recalc($1);
 2539: 		$current_length=~/(\d+\.?\d*)/;
 2540: 		if ($fwidth<$1) {$fwidth=$1;}
 2541: 		$garbage_data=~s/\\epsfxsize\s*=\s*(\d+\.?\d*\s*(mm|cm|in|pc|pt)*)//;
 2542: 	    }
 2543: 	    push @ {$Apache::londefdef::table[-1]{'TeXlen'}[$Apache::londefdef::table[-1]{'row_number'}] },'0';
 2544: 	    push @ {$Apache::londefdef::table[-1]{'objectlen'}[$Apache::londefdef::table[-1]{'row_number'}] },$fwidth;
 2545: 	    push @ {$Apache::londefdef::table[-1]{'minlen'}[$Apache::londefdef::table[-1]{'row_number'}] },'0';
 2546: 	    push @ {$Apache::londefdef::table[-1]{'maxlen'}[$Apache::londefdef::table[-1]{'row_number'}] },'0';
 2547: 	    $data=~s/\\\\\s*$//; 
 2548: 	} else {  
 2549: 	    $data=~s/^\s+(\S.*)/$1/; 
 2550: 	    $data=~s/(.*\S)\s+$/$1/;
 2551: 	    $data=~s/(\s)+/$1/;
 2552: 	    my ($current_length,$min_length)=(0,0);
 2553: 	    if ($data=~/\\vskip/) {
 2554:                 my $newdata=$data;
 2555: 		$newdata=~s/\\vskip \d*\.?\d*\s*mm/THISISJUSTTEMPORARYSEPARATOR/g;
 2556: 		my @newdata=split(/THISISJUSTTEMPORARYSEPARATOR/,$newdata);
 2557: 		foreach my $elementdata (@newdata) {
 2558: 		    my $lengthnewdata=2.5*&LATEX_length($elementdata);
 2559: 		    if ($lengthnewdata>$current_length) {$current_length=$lengthnewdata;}
 2560:                     my @words=split(/ /,$elementdata);
 2561: 		    foreach my $word (@words) {
 2562: 			my $lengthword=2.5*&LATEX_length($word);
 2563: 			if ($min_length<$lengthword) {$min_length=$lengthword;}
 2564: 		    }
 2565: 		}
 2566: 	    } else {
 2567: 		$current_length=2.5*&LATEX_length($data);
 2568:                     my @words=split(/ /,$data);
 2569: 		    foreach my $word (@words) {
 2570: 			my $lengthword=2*&LATEX_length($word);
 2571: 			if ($min_length<$lengthword) {$min_length=$lengthword;}
 2572: 		    }
 2573: 	    }
 2574: 	    push @ {$Apache::londefdef::table[-1]{'TeXlen'}[$Apache::londefdef::table[-1]{'row_number'}] },'0';
 2575: 	    push @ {$Apache::londefdef::table[-1]{'objectlen'}[$Apache::londefdef::table[-1]{'row_number'}] },'0';
 2576: 	    push @ {$Apache::londefdef::table[-1]{'maxlen'}[$Apache::londefdef::table[-1]{'row_number'}] },$current_length;
 2577: 	    push @ {$Apache::londefdef::table[-1]{'minlen'}[$Apache::londefdef::table[-1]{'row_number'}] },$min_length;
 2578: 	}        
 2579:     }
 2580:     # Substitute all of the tables nested in this cell in their appropriate places.
 2581: 
 2582: 
 2583:     my $nested_count = $#{$Apache::londefdef::table[-1]{'include'}}; # This one is constant...
 2584:     for (my $in=0; $in<=$nested_count; $in++) {    
 2585: 	my $nested = shift @{$Apache::londefdef::table[-1]{'include'}};
 2586: 	$nested =~ s/\\end\{tabular\}\\strut\\\\/\\end\{tabular\}/;
 2587: 	# $data=~s/\\keephidden\{NEW TABLE ENTRY\}/$Apache::londefdef::table[-1]{'include'}[$in]/;
 2588: 	$data =~ s/\\keephidden\{NEW TABLE ENTRY\}/$nested/;
 2589: 
 2590:     }
 2591:     # Should be be killing off the 'include' elements as they're used up?
 2592: 
 2593:     push @ {$Apache::londefdef::table[-1]{'content'}[-1] },$data;
 2594: 
 2595: 
 2596: 
 2597: 
 2598:     #  the colspan array will indicate how many columns will be spanned by this
 2599:     #  cell..this requires that counter_columns also be adjusted accordingly
 2600:     #  so that the next bunch of text goes in the right cell.  Note that since
 2601:     #  counter_columns is incremented in the start_td_tex, we adjust by colspan-1.
 2602:     #
 2603: 
 2604:     $Apache::londefdef::table[-1]{'counter_columns'} += $colspan -1;
 2605:     for (my $i = 0; $i < ($colspan -1); $i++) {
 2606: 	push @ {$Apache::londefdef::table[-1]{'content'}[-1] },'';
 2607:     }
 2608:     for (my $r = 0; $r < $rowspan; $r++) {
 2609: 	$Apache::londefdef::table[-1]{'colspan'}[$current_row+$r][$current_column] = $colspan;
 2610: 	# Put empty text in spanned cols.
 2611: 	
 2612:     }
 2613: 
 2614: 
 2615: 
 2616:     return '';
 2617: }
 2618: 
 2619: sub end_td {
 2620:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 2621:     my $currentstring = '';
 2622:     if ($target eq 'web' || $target eq 'webgrade') {
 2623: 	$currentstring = $token->[2];     
 2624:     } elsif ($target eq 'tex') {
 2625:         $Apache::londefdef::TD_redirection =0;
 2626: 	&end_td_tex($parstack,$parser,$safeeval);
 2627:     }
 2628:     return $currentstring;
 2629: }
 2630: 
 2631: #-- <th> tag (end tag optional)
 2632: sub start_th {
 2633:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 2634:     my $currentstring = '';
 2635:     if ($target eq 'web' || $target eq 'webgrade') {
 2636: 	$currentstring = $token->[4];     
 2637:     } elsif ($target eq 'tex') {
 2638: 	$Apache::londefdef::TD_redirection = 1;
 2639: 	&tagg_check('tr','th',$tagstack,$parstack,$parser,$safeeval);
 2640:     } 
 2641:     return $currentstring;
 2642: }   
 2643:     
 2644: sub tagg_check {
 2645:     my ($good_tag,$bad_tag,$tagstack,$parstack,$parser,$safeeval) = @_;
 2646:     my @ar=@$parstack; 
 2647:     for (my $i=$#ar-1;$i>=0;$i--) {
 2648: 	if (lc($$tagstack[$i]) eq $good_tag) {
 2649: 	    &start_th_tex($parstack,$parser,$safeeval);
 2650: 	    last;
 2651: 	} elsif (lc($$tagstack[$i]) eq $bad_tag) {
 2652: 	    splice @ar, $i+1;
 2653: 	    &end_th_tex(\@ar,$parser,$safeeval);
 2654: 	    &start_th_tex($parstack,$parser,$safeeval);
 2655: 	    last;
 2656: 	}
 2657:     }
 2658:     return '';
 2659: }
 2660:  
 2661: sub start_th_tex {
 2662:     my ($parstack,$parser,$safeeval) = @_;
 2663:     my $alignchar = substr(&Apache::lonxml::get_param('align',$parstack,$safeeval,undef,1),0,1);
 2664:     if ($alignchar eq '') {
 2665: 	$alignchar = $Apache::londefdef::table[-1]{'rows'}[-1];
 2666:     }
 2667:     push @{ $Apache::londefdef::table[-1]{'align'}[$Apache::londefdef::table[-1]{'row_number'}] }, $alignchar;
 2668:     $Apache::londefdef::table[-1]{'counter_columns'}++;
 2669:     my $TeXwidth=&Apache::lonxml::get_param('TeXwidth',$parstack,$safeeval,undef,0);
 2670:     if (defined $TeXwidth) {		
 2671: 	my $current_length=&recalc($TeXwidth);
 2672: 	$current_length=~/(\d+\.?\d*)/;
 2673: 	push @ {$Apache::londefdef::table[-1]{'TeXlen'}[$Apache::londefdef::table[-1]{'row_number'}] },$1;
 2674:     }
 2675:     &Apache::lonxml::startredirection();
 2676:     return '';
 2677: }
 2678: 
 2679: sub end_th_tex {
 2680:     my ($parstack,$parser,$safeeval) = @_;
 2681:     my $current_row = $Apache::londefdef::table[-1]{'row_number'};
 2682:     my $data=&Apache::lonxml::endredirection();
 2683:     my $TeXwidth=&Apache::lonxml::get_param('TeXwidth',$parstack,$safeeval,undef,0);
 2684:     if (defined $TeXwidth) {		
 2685: 	push @ {$Apache::londefdef::table[-1]{'objectlen'}[$Apache::londefdef::table[-1]{'row_number'}] },'0';
 2686: 	push @ {$Apache::londefdef::table[-1]{'minlen'}[$Apache::londefdef::table[-1]{'row_number'}] },'0';
 2687: 	push @ {$Apache::londefdef::table[-1]{'maxlen'}[$Apache::londefdef::table[-1]{'row_number'}] },'0';
 2688:     } else {
 2689: 	if (($data=~m/width\s*=\s*(\d+\.?\d*\s*(mm|cm|in|pc|pt)*)/) or ($data=~m/\[(\d+\.?\d*)\s*mm\]/)) {
 2690: 	    my $garbage_data=$data;
 2691: 	    my $fwidth=0;
 2692:             while ($garbage_data=~m/width\s*=\s*(\d+\.?\d*\s*(mm|cm|in|pc|pt)*)/) {
 2693: 		my $current_length=&recalc($1);
 2694: 		$current_length=~/(\d+\.?\d*)/;
 2695: 		if ($fwidth<$1) {$fwidth=$1;}
 2696: 		$garbage_data=~s/width\s*=\s*(\d+\.?\d*\s*(mm|cm|in|pc|pt)*)//;
 2697: 	    }
 2698:             while ($garbage_data=~m/\[(\d+\.?\d*)\s*mm\]/) {
 2699: 		my $current_length=$1;
 2700: 		if ($fwidth<$current_length) {$fwidth=$current_length;}
 2701: 		$garbage_data=~s/\[(\d+\.?\d*)\s*mm\]//;
 2702: 	    }
 2703: 	    push @ {$Apache::londefdef::table[-1]{'TeXlen'}[$Apache::londefdef::table[-1]{'row_number'}] },'0';
 2704: 	    push @ {$Apache::londefdef::table[-1]{'objectlen'}[$Apache::londefdef::table[-1]{'row_number'}] },$fwidth;
 2705: 	    push @ {$Apache::londefdef::table[-1]{'minlen'}[$Apache::londefdef::table[-1]{'row_number'}] },'0';
 2706: 	    push @ {$Apache::londefdef::table[-1]{'maxlen'}[$Apache::londefdef::table[-1]{'row_number'}] },'0';
 2707: 	} else {  
 2708: 	    $data=~s/^\s+(\S.*)/$1/; 
 2709: 	    $data=~s/(.*\S)\s+$/$1/;
 2710: 	    $data=~s/(\s)+/$1/;
 2711: 	    my ($current_length,$min_length)=(0,0);
 2712: 	    if ($data=~/\\vskip/) {
 2713:                 my $newdata=$data;
 2714: 		$newdata=~s/\\vskip \d*\.?\d*\s*mm/THISISJUSTTEMPORARYSEPARATOR/g;
 2715: 		my @newdata=split(/THISISJUSTTEMPORARYSEPARATOR/,$newdata);
 2716: 		foreach my $elementdata (@newdata) {
 2717: 		    my $lengthnewdata=2.5*&LATEX_length($elementdata);
 2718: 		    if ($lengthnewdata>$current_length) {$current_length=$lengthnewdata;}
 2719:                     my @words=split(/ /,$elementdata);
 2720: 		    foreach my $word (@words) {
 2721: 			my $lengthword=2.5*&LATEX_length($word);
 2722: 			if ($min_length<$lengthword) {$min_length=$lengthword;}
 2723: 		    }
 2724: 		}
 2725: 	    } else {
 2726: 		$current_length=2.5*&LATEX_length($data);
 2727:                     my @words=split(/ /,$data);
 2728: 		    foreach my $word (@words) {
 2729: 			my $lengthword=2*&LATEX_length($word);
 2730: 			if ($min_length<$lengthword) {$min_length=$lengthword;}
 2731: 		    }
 2732: 	    }
 2733: 	    push @ {$Apache::londefdef::table[-1]{'TeXlen'}[$Apache::londefdef::table[-1]{'row_number'}] },'0';
 2734: 	    push @ {$Apache::londefdef::table[-1]{'objectlen'}[$Apache::londefdef::table[-1]{'row_number'}] },'0';
 2735: 	    push @ {$Apache::londefdef::table[-1]{'maxlen'}[$Apache::londefdef::table[-1]{'row_number'}] },$current_length;
 2736: 	    push @ {$Apache::londefdef::table[-1]{'minlen'}[$Apache::londefdef::table[-1]{'row_number'}] },$min_length;
 2737: 	}        
 2738:     }
 2739: 	for (my $in=0; $in<=$#{$Apache::londefdef::table[-1]{'include'}};$in++) {         
 2740: 	    $data=~s/\\keephidden\{NEW TABLE ENTRY\}/$Apache::londefdef::table[-1]{'include'}[$in]/;
 2741: 	}
 2742:     #make data bold
 2743:     $data='\textbf{'.$data.'}';
 2744:     push @ {$Apache::londefdef::table[-1]{'content'}[-1] },$data;
 2745:     return'';
 2746: }
 2747: 
 2748: sub end_th {
 2749:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 2750:     my $currentstring = &end_p();	# Close any open <p> in the row.
 2751:     if ($target eq 'web' || $target eq 'webgrade') {
 2752: 	$currentstring .= $token->[2];     
 2753:     } elsif ($target eq 'tex') {
 2754:         $Apache::londefdef::TD_redirection =0;
 2755: 	&end_th_tex($parstack,$parser,$safeeval);
 2756:     }
 2757:     return $currentstring;
 2758: }
 2759:      
 2760: #-- <img> tag (end tag forbidden)
 2761: #
 2762: #  Render the <IMG> tag.
 2763: #     <IMG> has the following attributes (in addition to the 
 2764: #     standard HTML ones:
 2765: #      TeXwrap   - Governs how the tex target will try to wrap text around
 2766: #                  horizontally aligned images.
 2767: #      TeXwidth  - The width of the image when rendered for print (mm).
 2768: #      TeXheight - The height of the image when rendered for print (mm)
 2769: #         (Note there seems to also be support for this as a % of page size)
 2770: #      
 2771: sub start_img {
 2772:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style) = @_;
 2773:     my $src = &Apache::lonxml::get_param('src',$parstack,$safeeval,
 2774: 					 undef,1);
 2775:     if (! $src && 
 2776: 	($target eq 'web' || $target eq 'webgrade' || $target eq 'tex')
 2777: 	) { 
 2778: 	my $inside = &Apache::lonxml::get_all_text("/img",$parser,$style);
 2779: 	return '';
 2780:     }
 2781:     &Apache::lonxml::extlink($src);
 2782:     my $currentstring = '';
 2783:     my $scaling = .3;
 2784: 
 2785:    # Render unto browsers that which are the browser's...
 2786: 
 2787:     if ($target eq 'web' || $target eq 'webgrade') {
 2788: 	if ($env{'browser.imagesuppress'} ne 'on') {
 2789: 	    my $enc = ('yes' eq 
 2790: 		       lc(&Apache::lonxml::get_param('encrypturl',$parstack,
 2791: 						     $safeeval)));
 2792: 	    $currentstring.=&Apache::lonenc::encrypt_ref($token,{'src'=>$src},
 2793: 							 $enc);
 2794: 	} else {
 2795: 	    my $alttag = &Apache::lonxml::get_param('alt',$parstack,$safeeval,
 2796: 						    undef,1);
 2797: 	    if (!$alttag) {
 2798: 		$alttag = &Apache::lonmeta::alttag($Apache::lonxml::pwd[-1],
 2799: 						   $src);
 2800: 	    }
 2801: 	    $currentstring.='[IMAGE: '.$alttag.']';
 2802: 	}
 2803: 
 2804: 	# and render unto TeX that which is LaTeX
 2805: 
 2806:     } elsif ($target eq 'tex') {
 2807: 	#
 2808: 	#  The alignment will require some superstructure to be put around
 2809: 	#  the \includegraphics stuff.  At present we can only partially
 2810: 	#  simulate the alignments offered by html.
 2811: 	#
 2812: 	#
 2813: 	my $align = lc(&Apache::lonxml::get_param('align', 
 2814: 						  $parstack,
 2815: 						  $safeeval,
 2816: 						  undef,1));
 2817: 	if(!$align) {
 2818: 		$align = "bottom";	# This is html's default so it's ours too.
 2819: 	}
 2820: 	#
 2821: 	&Apache::lonxml::debug("Alignemnt = $align");
 2822: 	#  LaTeX's image/text wrapping is really bad since it wants to
 2823: 	#  make figures float.  
 2824:         #   The user has the optional parameter (applicable only to l/r
 2825: 	# alignment to use the picins/parpic directive to get wrapped text
 2826: 	# this is also imperfect.. that's why we give them a choice...
 2827: 	# so they can't yell at us for our choice.
 2828: 	#
 2829: 	my $latex_rendering = &Apache::lonxml::get_param('TeXwrap',
 2830: 							    $parstack,
 2831: 							    $safeeval,
 2832: 							    undef,0);
 2833: 	# &Apache::lonxml::debug("LaTeX rendering = $latex_rendering");
 2834: 	if(!$latex_rendering) {
 2835: 		$latex_rendering = "texwrap";
 2836: 	}
 2837: 	# using texwrap inside a table does not work. So, if after all of this,
 2838: 	# texwrap is on, we turn it off if we detect we're in a table:
 2839: 	#
 2840: 	if (($latex_rendering eq 'texwrap') && &is_inside_of($tagstack, "table")) {
 2841: 	    $latex_rendering = 'parpic';
 2842: 	}
 2843: 
 2844: 	# &Apache::lonxml::debug("LaTeX rendering = $latex_rendering image file: $src");
 2845: 
 2846: 	#if original gif/jpg/png file exist do following:
 2847: 	my $origsrc=$src;
 2848: 	my ($path,$file) = &get_eps_image($src);
 2849: 	$src=&Apache::lonnet::filelocation($Apache::lonxml::pwd[-1],$src);
 2850: 	&Apache::lonxml::debug("path = $path file = $file src = $src");
 2851: 	if (-e $src) {
 2852: 	    &Apache::lonxml::debug("$src exists");
 2853: 	    my ($height_param,$width_param)=
 2854: 		&image_size($origsrc,0.3,$parstack,$safeeval);
 2855: 	    my $destpath = $path;
 2856: 	    $destpath    =~ s/ /\_/g; # Spaces in path cause LaTex to vomit.
 2857: 	    my $destfile = $file;
 2858: 	    $destfile    =~ s/ /\_/g;
 2859: 	    my $size;
 2860: 	    if ($width_param)  { $size.='width='.$width_param.' mm,'; }
 2861: 	    if ($height_param) { $size.='height='.$height_param.' mm]'; }
 2862: 	    $size='['.$size;
 2863: 	    $size=~s/,$/]/; 
 2864: 	    $currentstring .= '\graphicspath{{'.$destpath.'}}'
 2865: 		.'\includegraphics'.$size.'{'.$destfile.'} ';
 2866: 
 2867: 	    #    If there's an alignment specification we need to honor it here.
 2868: 	    #    For the horizontal alignments, we will also honor the
 2869: 	    #    value of the latex specfication.  The default is parbox,
 2870: 	    #    and that's used for illegal values too.  
 2871: 	    #    
 2872: 	    #    Even though we set a default alignment value, the user
 2873: 	    #    could have given us an illegal value.  In that case we
 2874: 	    #    just use the default alignment of bottom..
 2875: 	    if      ($align eq "top")    {
 2876: 		$currentstring = '\raisebox{-'.$height_param.'mm}{'.$currentstring.'}';
 2877: 	    } elsif (($align eq "center") || ($align eq "middle")) { # Being kind
 2878: 		my $offset = $height_param/2;
 2879: 		$currentstring = '\raisebox{-'.$offset.'mm}{'.$currentstring.'}';
 2880: 	    } elsif ($align eq "left")   { 
 2881: 		if ($latex_rendering eq "parpic") { 
 2882: 		    $currentstring = '\parpic[l]{'.$currentstring.'}';
 2883: 		} else {    	                                 # wrapfig render
 2884: 		    $currentstring = '\begin{wrapfigure}{l}{'.$width_param.'mm}'
 2885: 			.'\scalebox{1.0}{'.$currentstring.'}\end{wrapfigure}';
 2886: 		}
 2887: 	    } elsif ($align eq "right")  {   
 2888: 		if ($latex_rendering eq "parpic") {
 2889: 		    $currentstring = '\parpic[r]{'.$currentstring.'}';
 2890: 		} else {	                                 # wrapfig rendering
 2891: 		    $currentstring = '\begin{wrapfigure}{r}{'.$width_param.'mm}'
 2892: 			.'\scalebox{1.0}{'.$currentstring.'}\end{wrapfigure}';
 2893: 
 2894: 		}
 2895: 	    } else {		# Bottom is also default.
 2896: 		# $currentstring = '\raisebox{'.$height_param.'mm}{'.$currentstring.'}';
 2897: 	    }
 2898: 	} else {
 2899: 	    &Apache::lonxml::debug("$src does not exist");
 2900: 	    #original image file doesn't exist so check the alt attribute
 2901: 	    my $alt = 
 2902: 		&Apache::lonxml::get_param('alt',$parstack,$safeeval,undef,1);
 2903: 	    unless ($alt) {
 2904: 		$alt=&Apache::lonmeta::alttag($Apache::lonxml::pwd[-1],$src);
 2905: 	    }
 2906: 
 2907: 	    if ($alt) { $currentstring .= ' '.$alt.' '; }
 2908: 	}
 2909: 
 2910: 	# And here's where the semi-quote breaks down: allow the user
 2911:         # to edit the beast as well by rendering the problem for edit:
 2912:     } elsif ($target eq 'edit') {
 2913: 	$currentstring .=&Apache::edit::tag_start($target,$token);
 2914: 	$currentstring .=&Apache::edit::text_arg('Image Url:','src',$token,70).
 2915: 	    &Apache::edit::browse('src',undef,'alt').' '.
 2916: 	    &Apache::edit::search('src',undef,'alt').'<br />';
 2917: 	$currentstring .=&Apache::edit::text_arg('Description:','alt',$token,70).'<br />';
 2918: 	$currentstring .=&Apache::edit::text_arg('width (pixel):','width',$token,5);
 2919: 	$currentstring .=&Apache::edit::text_arg('height (pixel):','height',$token,5).'<br />';
 2920: 	$currentstring .=&Apache::edit::text_arg('TeXwidth (mm):','TeXwidth',$token,5);
 2921: 	$currentstring .=&Apache::edit::text_arg('TeXheight (mm):','TeXheight',$token,5);
 2922: 	$currentstring .=&Apache::edit::select_arg('Alignment:','align',
 2923: 						   ['','bottom','middle','top','left','right'],$token,5);
 2924: 	$currentstring .=&Apache::edit::select_arg('TeXwrap:', 'TeXwrap',
 2925: 						   ['', 'parbox', 'parpic'], $token, 2);
 2926: 	$currentstring .=&Apache::edit::select_arg('Encrypt URL:','encrypturl',
 2927: 						   ['no','yes'], $token, 2);
 2928: 	$currentstring .=&Apache::edit::end_row().&Apache::edit::start_spanning_row();
 2929: 	my $src=    &Apache::lonxml::get_param('src',$parstack,$safeeval);
 2930: 	my $alt=    &Apache::lonxml::get_param('alt',$parstack,$safeeval);
 2931: 	my $width=  &Apache::lonxml::get_param('width',$parstack,$safeeval);
 2932: 	my $height= &Apache::lonxml::get_param('height',$parstack,$safeeval);
 2933: 
 2934: 
 2935: 	$currentstring .= '<img src="'.$src.'" alt="'.$alt.'" ';
 2936: 	if ($width) { $currentstring.=' width="'.$width.'" '; }
 2937: 	if ($height) { $currentstring.=' height="'.$height.'" '; }
 2938: 	$currentstring .= ' />';
 2939:     } elsif ($target eq 'modified') {
 2940: 	my ($osrc,$owidth,$oheight)=
 2941: 	    ($token->[2]{'src'},$token->[2]{'width'},$token->[2]{'height'});
 2942: 	my $ctag=&Apache::edit::get_new_args($token,$parstack,
 2943: 					     $safeeval,'src','alt','align',
 2944: 					     'TeXwidth','TeXheight', 'TeXwrap',
 2945: 					     'width','height','encrypturl');
 2946: 	my ($nsrc,$nwidth,$nheight)=
 2947: 	    ($token->[2]{'src'},$token->[2]{'width'},$token->[2]{'height'});
 2948: 	my $loc=&Apache::lonnet::filelocation($Apache::lonxml::pwd[-1],$nsrc);
 2949: 	&image_replication($loc);
 2950: 	my ($iwidth,$iheight);
 2951: 	if (-e $loc) {
 2952: 	    my $image = Image::Magick->new;
 2953: 	    $image->Read($loc);
 2954: 	    ($iwidth, $iheight) = ($image->Get('width'),
 2955: 				   $image->Get('height'));
 2956: 	}
 2957: 	if ($osrc ne $nsrc || (!$nwidth && !$nheight)) {
 2958: 	    # changed image or no size specified,
 2959:             # if they didn't explicitly change the 
 2960:             # width or height use the ones from the image
 2961: 	    if ($iwidth && $iheight) {
 2962: 		if ($owidth == $nwidth || (!$nwidth && !$nheight)) {
 2963: 		    $token->[2]{'width'} = $iwidth;$ctag=1;
 2964: 		}
 2965: 		if ($oheight == $nheight || (!$nwidth && !$nheight)) {
 2966: 		    $token->[2]{'height'}=$iheight;$ctag=1;
 2967: 		}
 2968: 	    }
 2969: 	}
 2970: 	my ($cwidth,$cheight)=($token->[2]{'width'},$token->[2]{'height'});
 2971: 	# if we don't have a width or height
 2972: 	if ($iwidth && $cwidth && !$cheight) {
 2973: 	    $token->[2]{'height'}=int(($cwidth/$iwidth)*$iheight);$ctag=1;
 2974: 	}
 2975: 	if ($iheight && $cheight && !$cwidth) {
 2976: 	    $token->[2]{'width'}=int(($cheight/$iheight)*$iwidth);$ctag=1;
 2977: 	}
 2978: 	if ($ctag) {$currentstring=&Apache::edit::rebuild_tag($token);}
 2979:     }
 2980: 
 2981:     return $currentstring;
 2982: }
 2983: 
 2984: sub end_img {
 2985:     my ($target,$token) = @_;
 2986:     my $currentstring = '';
 2987:     if ($target eq 'web' || $target eq 'webgrade') {
 2988: 	$currentstring = $token->[2];
 2989:     } elsif ($target eq 'tex') {
 2990: 	$currentstring = '';
 2991:     }
 2992:     return $currentstring;
 2993: }
 2994: 
 2995: #-- <applet> tag (end tag required)
 2996: sub start_applet {
 2997:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 2998:     
 2999:     my $code=&Apache::lonxml::get_param('code',$parstack,$safeeval,undef,1);
 3000:     &Apache::lonxml::extlink($code);
 3001:     my $archive=&Apache::lonxml::get_param('archive',$parstack,$safeeval,
 3002: 					   undef,1);
 3003:     &Apache::lonxml::extlink($archive);
 3004:     my $currentstring = '';
 3005:     if ($target eq 'web' || $target eq 'webgrade') {
 3006: 	if ($env{'browser.appletsuppress'} ne 'on') {
 3007: 	    $currentstring = &Apache::lonenc::encrypt_ref($token,
 3008: 							  {'code'=>$code,
 3009: 							   'archive'=>$archive}
 3010: 							  );
 3011: 	} else {
 3012: 	    my $alttag= &Apache::lonxml::get_param('alt',$parstack,
 3013: 						   $safeeval,undef,1);
 3014: 	    unless ($alttag) {
 3015: 		$alttag=&Apache::lonmeta::alttag($Apache::lonxml::pwd[-1],
 3016: 						 $code);
 3017: 	    }
 3018: 	    $currentstring='[APPLET: '.$alttag.']';
 3019: 	}
 3020:     } elsif ($target eq 'tex') {
 3021: 	my $alttag= &Apache::lonxml::get_param('alt',$parstack,
 3022: 					       $safeeval,undef,1);
 3023: 	unless ($alttag) {
 3024: 	    my $code=&Apache::lonxml::get_param('code',$parstack,$safeeval,
 3025: 						undef,1);
 3026: 	    $alttag=&Apache::lonmeta::alttag($Apache::lonxml::pwd[-1],
 3027: 					     $code);
 3028: 	}
 3029: 	$currentstring.='\begin{center} \fbox{Java Applet: '.$alttag.
 3030: 	    '.}\end{center}';
 3031:     } 
 3032:     return $currentstring;
 3033: }
 3034: 
 3035: sub end_applet {
 3036:     my ($target,$token) = @_;
 3037:     my $currentstring = '';
 3038:     if ($target eq 'web' || $target eq 'webgrade') {
 3039: 	$currentstring = $token->[2];
 3040:     } elsif ($target eq 'tex') {
 3041:     } 
 3042:     return $currentstring;
 3043: }
 3044: 
 3045: #-- <embed> tag (end tag optional/required)
 3046: sub start_embed {    
 3047:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 3048:     my $src=&Apache::lonxml::get_param('src',$parstack,$safeeval,undef,1);
 3049:     &Apache::lonxml::extlink($src);
 3050:     my $currentstring = '';
 3051:     if ($target eq 'web' || $target eq 'webgrade') {
 3052: 	if ($env{'browser.embedsuppress'} ne 'on') {
 3053: 	    $currentstring=&Apache::lonenc::encrypt_ref($token,{'src'=>$src});
 3054: 	} else {
 3055: 	    my $alttag=&Apache::lonxml::get_param
 3056: 		('alt',$parstack,$safeeval,undef,1);
 3057: 	    unless ($alttag) {
 3058: 		$alttag=&Apache::lonmeta::alttag($Apache::lonxml::pwd[-1],$src);
 3059: 	    }
 3060: 	    $currentstring='[EMBED: '.$alttag.']';
 3061: 	}
 3062:     } elsif ($target eq 'tex') {
 3063:     } 
 3064:     return $currentstring;
 3065: }
 3066: 
 3067: sub end_embed {
 3068:     my ($target,$token) = @_;
 3069:     my $currentstring = '';
 3070:     if ($target eq 'web' || $target eq 'webgrade') {
 3071: 	$currentstring = $token->[2];     
 3072:     } elsif ($target eq 'tex') {  
 3073:     } 
 3074:     return $currentstring;
 3075: }
 3076: 
 3077: #-- <param> tag (end tag forbidden)
 3078: sub start_param {
 3079:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 3080:     if (&Apache::lonxml::get_param('name',$parstack,
 3081: 				   $safeeval,undef,1)=~/^cabbase$/i) {
 3082: 	my $value=&Apache::lonxml::get_param('value',$parstack,
 3083: 					     $safeeval,undef,1);
 3084: 	&Apache::lonxml::extlink($value);
 3085:     } 
 3086:   
 3087:     my $src = &Apache::lonxml::get_param('src',$parstack,$safeeval,undef,1);
 3088:     &Apache::lonxml::extlink($src);
 3089:     my $currentstring = '';
 3090:     if ($target eq 'web' || $target eq 'webgrade') {
 3091: 	my %toconvert;
 3092: 	my $src=&Apache::lonxml::get_param('src',$parstack,$safeeval,undef,1);
 3093: 	if ($src) { $toconvert{'src'}= $src; }
 3094: 	my $name=&Apache::lonxml::get_param('name',$parstack,$safeeval,
 3095: 					    undef,1);
 3096: 	if ($name=~/^cabbase$/i) {
 3097: 	    $toconvert{'value'}=&Apache::lonxml::get_param('value',$parstack,
 3098: 							   $safeeval,undef,1);
 3099: 	}
 3100: 	$currentstring = &Apache::lonenc::encrypt_ref($token,\%toconvert);
 3101:     } elsif ($target eq 'tex') {
 3102:     } 
 3103:     return $currentstring;
 3104: }
 3105: 
 3106: sub end_param {
 3107:     my ($target,$token) = @_;
 3108:     my $currentstring = '';
 3109:     if ($target eq 'web' || $target eq 'webgrade') {
 3110: 	$currentstring = $token->[2];     
 3111:     } elsif ($target eq 'tex') {
 3112:     } 
 3113:     return $currentstring;
 3114: }
 3115: 
 3116: #-- <allow> tag
 3117: sub start_allow {
 3118:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 3119:     my $src = &Apache::lonxml::get_param('src',$parstack,$safeeval,undef,1);
 3120:     &Apache::lonxml::extlink($src);
 3121: 
 3122:     if ($target eq 'tex') { &image_replication($src); }
 3123:     my $result;
 3124:     if ($target eq 'edit') {
 3125: 	$result .=&Apache::edit::tag_start($target,$token);
 3126: 	$result .=&Apache::edit::text_arg('File Spec:','src',$token,70);
 3127: 	$result .=&Apache::edit::end_row();#.&Apache::edit::start_spanning_row();
 3128:     } elsif ($target eq 'modified') {
 3129: 	my $constructtag=&Apache::edit::get_new_args($token,$parstack,
 3130: 						     $safeeval,'src');
 3131: 	if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); }
 3132:     }
 3133:     return $result;
 3134: }
 3135: 
 3136: sub end_allow {
 3137:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 3138:     if ( $target eq 'edit') { return (&Apache::edit::end_table()); }
 3139:     return '';
 3140: }
 3141: 
 3142: #-- Frames (end tag required)
 3143: #-- <frameset>
 3144: sub start_frameset {
 3145:     my ($target,$token) = @_;
 3146:     my $currentstring = '';	# Close any pending para.
 3147:     if ($target eq 'web' || $target eq 'webgrade') { 
 3148: 	$currentstring = 
 3149: 	    &Apache::loncommon::start_page($Apache::londefdef::title,
 3150: 					   $Apache::londefdef::head,
 3151: 					   {'add_entries'    => $token->[2],
 3152: 					    'no_title'       => 1,
 3153: 					    'force_register' => 1,
 3154: 					    'frameset'       => 1,});
 3155: 
 3156:     }
 3157:     return $currentstring;
 3158: }
 3159: 
 3160: sub end_frameset {
 3161:     my ($target,$token) = @_;
 3162:     my $currentstring = '';
 3163:     if ($target eq 'web' || $target eq 'webgrade') {
 3164: 	$currentstring = $token->[2];
 3165:     }
 3166:     return $currentstring;
 3167: }
 3168: 
 3169: #-- <xmp> (end tag required)
 3170: sub start_xmp {
 3171:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 3172:     my $currentstring = '';
 3173:     if ($target eq 'web' || $target eq 'webgrade') {
 3174: 	$currentstring .= $token->[4];
 3175:     } elsif ($target eq 'tex') {
 3176: 	$currentstring .= '\begin{verbatim}';
 3177:     } 
 3178:     return $currentstring;
 3179: }
 3180: 
 3181: sub end_xmp {
 3182:     my ($target,$token) = @_;
 3183:     my $currentstring = '';
 3184:     if ($target eq 'web' || $target eq 'webgrade') {
 3185: 	$currentstring .= $token->[2];
 3186:     } elsif ($target eq 'tex') {
 3187: 	$currentstring .= '\end{verbatim}';
 3188:     }
 3189:     return $currentstring;
 3190: }
 3191: 
 3192: #-- <pre> (end tag required)
 3193: sub start_pre {
 3194:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 3195:     my $currentstring = &end_p();	# close off pending <p>
 3196:     if ($target eq 'web' || $target eq 'webgrade') {
 3197: 	$currentstring .= $token->[4];
 3198:     } elsif ($target eq 'tex') {
 3199: 	$currentstring .= '\begin{verbatim}';
 3200: 	&Apache::lonxml::disable_LaTeX_substitutions();
 3201:     } 
 3202:     return $currentstring;
 3203: }
 3204: 
 3205: sub end_pre {
 3206:     my ($target,$token) = @_;
 3207:     my $currentstring = '';
 3208:     if ($target eq 'web' || $target eq 'webgrade') {
 3209: 	$currentstring .= $token->[2];
 3210:     } elsif ($target eq 'tex') {
 3211: 	$currentstring .= '\end{verbatim}';
 3212: 	&Apache::lonxml::enable_LaTeX_substitutions();
 3213:     }
 3214:     return $currentstring;
 3215: }
 3216: 
 3217: #-- <insert>
 3218: sub start_insert {
 3219:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 3220:     my $currentstring = '';
 3221:     if ($target eq 'web' || $target eq 'webgrade') {
 3222: 	my $display = &Apache::lonxml::get_param('display',$parstack,$safeeval,undef,1);
 3223: 	$currentstring .= '<b>'.$display.'</b>';;
 3224:     }
 3225:     return $currentstring;
 3226: }
 3227: 
 3228: sub end_insert {
 3229:     my ($target,$token) = @_;
 3230:     my $currentstring = '';
 3231:     if ($target eq 'web' || $target eq 'webgrade') {
 3232: 	$currentstring .= '';
 3233:     }
 3234:     return $currentstring;
 3235: }
 3236: 
 3237: #-- <externallink>
 3238: sub start_externallink {
 3239:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 3240:     my $currentstring = '';
 3241:     if ($target eq 'web' || $target eq 'webgrade') {
 3242: 	my $display = &Apache::lonxml::get_param('display',$parstack,$safeeval,undef,1);
 3243: 	$currentstring .= '<b>'.$display.'</b>';;
 3244:     }
 3245:     return $currentstring;
 3246: }
 3247: 
 3248: sub end_externallink {
 3249:     my ($target,$token) = @_;
 3250:     my $currentstring = '';
 3251:     if ($target eq 'web' || $target eq 'webgrade') {
 3252: 	$currentstring .= '';
 3253:     }
 3254:     return $currentstring;
 3255: }
 3256: 
 3257: #-- <blankspace heigth="">
 3258: sub start_blankspace {
 3259:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 3260:     my $currentstring = &end_p();	# closes off any unclosed <p>
 3261:     if ($target eq 'tex') {
 3262: 	my $howmuch = &Apache::lonxml::get_param('heigth',$parstack,$safeeval,undef,1);
 3263: 	$currentstring .= '\vskip '.$howmuch.' ';
 3264:     }
 3265:     return $currentstring;
 3266: }
 3267: 
 3268: sub end_blankspace {
 3269:     my ($target,$token) = @_;
 3270:     my $currentstring = '';
 3271:     if ($target eq 'tex') {
 3272: 	$currentstring .= '';
 3273:     }
 3274:     return $currentstring;
 3275: }
 3276: 
 3277: #-- <abbr> tag (end tag required)
 3278: sub start_abbr {
 3279:     my ($target,$token) = @_;
 3280:     my $currentstring = '';
 3281:     if ($target eq 'web' || $target eq 'webgrade') {
 3282: 	$currentstring = $token->[4];     
 3283:     } 
 3284:     return $currentstring;
 3285: }
 3286: 
 3287: sub end_abbr {
 3288:     my ($target,$token) = @_;
 3289:     my $currentstring = '';
 3290:     if ($target eq 'web' || $target eq 'webgrade') {
 3291: 	$currentstring = $token->[2];    
 3292:     } 
 3293:     return $currentstring;
 3294: }
 3295: 
 3296: #-- <acronym> tag (end tag required)
 3297: sub start_acronym {
 3298:     my ($target,$token) = @_;
 3299:     my $currentstring = '';
 3300:     if ($target eq 'web' || $target eq 'webgrade') {
 3301: 	$currentstring = $token->[4];     
 3302:     } 
 3303:     return $currentstring;
 3304: }
 3305: 
 3306: sub end_acronym {
 3307:     my ($target,$token) = @_;
 3308:     my $currentstring = '';
 3309:     if ($target eq 'web' || $target eq 'webgrade') {
 3310: 	$currentstring = $token->[2];    
 3311:     } 
 3312:     return $currentstring;
 3313: }
 3314: 
 3315: #-- <area> tag (end tag forbidden)
 3316: sub start_area {
 3317:     my ($target,$token) = @_;
 3318:     my $currentstring = '';
 3319:     if ($target eq 'web' || $target eq 'webgrade') {
 3320: 	$currentstring = $token->[4];     
 3321:     } 
 3322:     return $currentstring;
 3323: }
 3324: 
 3325: sub end_area {
 3326:     my ($target,$token) = @_;
 3327:     my $currentstring = '';
 3328:     if ($target eq 'web' || $target eq 'webgrade') {
 3329: 	$currentstring = $token->[2];    
 3330:     } 
 3331:     return $currentstring;
 3332: }
 3333: 
 3334: #-- <base> tag (end tag forbidden)
 3335: sub start_base {
 3336:     my ($target,$token) = @_;
 3337:     my $currentstring = '';
 3338:     if ($target eq 'web' || $target eq 'webgrade') {
 3339: 	$currentstring = $token->[4];     
 3340:     }
 3341:     return $currentstring;
 3342: }
 3343: 
 3344: sub end_base {
 3345:     my ($target,$token) = @_;
 3346:     my $currentstring = '';
 3347:     if ($target eq 'web' || $target eq 'webgrade') {
 3348: 	$currentstring = $token->[2];    
 3349:     } 
 3350:     return $currentstring;
 3351: }
 3352: 
 3353: #-- <bdo> tag (end tag required)
 3354: sub start_bdo {
 3355:     my ($target,$token) = @_;
 3356:     my $currentstring = '';
 3357:     if ($target eq 'web' || $target eq 'webgrade') {
 3358: 	$currentstring = $token->[4];     
 3359:     } 
 3360:     return $currentstring;
 3361: }
 3362: 
 3363: sub end_bdo {
 3364:     my ($target,$token) = @_;
 3365:     my $currentstring = '';
 3366:     if ($target eq 'web' || $target eq 'webgrade') {
 3367: 	$currentstring = $token->[2];    
 3368:     } 
 3369:     return $currentstring;
 3370: }
 3371: 
 3372: #-- <bgsound> tag (end tag optional)
 3373: sub start_bgsound {
 3374:     my ($target,$token) = @_;
 3375:     my $currentstring = '';
 3376:     if ($target eq 'web' || $target eq 'webgrade') {
 3377: 	$currentstring = $token->[4];     
 3378:     } 
 3379:     return $currentstring;
 3380: }
 3381: 
 3382: sub end_bgsound {
 3383:     my ($target,$token) = @_;
 3384:     my $currentstring = '';
 3385:     if ($target eq 'web' || $target eq 'webgrade') {
 3386: 	$currentstring = $token->[2];    
 3387:     } 
 3388:     return $currentstring;
 3389: }
 3390: 
 3391: #-- <blink> tag (end tag required)
 3392: sub start_blink {
 3393:     my ($target,$token) = @_;
 3394:     my $currentstring = '';
 3395:     if ($target eq 'web' || $target eq 'webgrade') {
 3396: 	$currentstring = $token->[4];     
 3397:     } 
 3398:     return $currentstring;
 3399: }
 3400: 
 3401: sub end_blink {
 3402:     my ($target,$token) = @_;
 3403:     my $currentstring = '';
 3404:     if ($target eq 'web' || $target eq 'webgrade') {
 3405: 	$currentstring = $token->[2];    
 3406:     } 
 3407:     return $currentstring;
 3408: }
 3409: 
 3410: #-- <blockquote> tag (end tag required)
 3411: sub start_blockquote {
 3412:     my ($target,$token) = @_;
 3413:     my $currentstring = &end_p();	# Close any unclosed <p>
 3414:     if ($target eq 'web' || $target eq 'webgrade') {
 3415: 	$currentstring .= $token->[4];     
 3416:     } 
 3417:     return $currentstring;
 3418: }
 3419: 
 3420: sub end_blockquote {
 3421:     my ($target,$token) = @_;
 3422:     my $currentstring = '';
 3423:     if ($target eq 'web' || $target eq 'webgrade') {
 3424: 	$currentstring = $token->[2];    
 3425:     } 
 3426:     return $currentstring;
 3427: }
 3428: 
 3429: #-- <button> tag (end tag required)
 3430: sub start_button {
 3431:     my ($target,$token) = @_;
 3432:     my $currentstring = '';
 3433:     if ($target eq 'web' || $target eq 'webgrade') {
 3434: 	$currentstring = $token->[4];     
 3435:     } 
 3436:     return $currentstring;
 3437: }
 3438: 
 3439: sub end_button {
 3440:     my ($target,$token) = @_;
 3441:     my $currentstring = '';
 3442:     if ($target eq 'web' || $target eq 'webgrade') {
 3443: 	$currentstring = $token->[2];    
 3444:     } 
 3445:     return $currentstring;
 3446: }
 3447: 
 3448: #-- <caption> tag (end tag required)
 3449: sub start_caption {
 3450:     my ($target,$token) = @_;
 3451:     my $currentstring = '';
 3452:     if ($target eq 'web' || $target eq 'webgrade') {
 3453: 	$currentstring = $token->[4];     
 3454:     } 
 3455:     return $currentstring;
 3456: }
 3457: 
 3458: sub end_caption {
 3459:     my ($target,$token) = @_;
 3460:     my $currentstring = '';
 3461:     if ($target eq 'web' || $target eq 'webgrade') {
 3462: 	$currentstring = $token->[2];    
 3463:     } 
 3464:     return $currentstring;
 3465: }
 3466: 
 3467: #-- <col> tag (end tag forbdden)
 3468: sub start_col {
 3469:     my ($target,$token) = @_;
 3470:     my $currentstring = '';
 3471:     if ($target eq 'web' || $target eq 'webgrade') {
 3472: 	$currentstring = $token->[4];     
 3473:     } 
 3474:     return $currentstring;
 3475: }
 3476: 
 3477: sub end_col {
 3478:     my ($target,$token) = @_;
 3479:     my $currentstring = '';
 3480:     if ($target eq 'web' || $target eq 'webgrade') {
 3481: 	$currentstring = $token->[2];    
 3482:     } 
 3483:     return $currentstring;
 3484: }
 3485: 
 3486: #-- <colgroup> tag (end tag optional)
 3487: sub start_colgroup {
 3488:     my ($target,$token) = @_;
 3489:     my $currentstring = '';
 3490:     if ($target eq 'web' || $target eq 'webgrade') {
 3491: 	$currentstring = $token->[4];     
 3492:     } 
 3493:     return $currentstring;
 3494: }
 3495: 
 3496: sub end_colgroup {
 3497:     my ($target,$token) = @_;
 3498:     my $currentstring = '';
 3499:     if ($target eq 'web' || $target eq 'webgrade') {
 3500: 	$currentstring = $token->[2];    
 3501:     } 
 3502:     return $currentstring;
 3503: }
 3504: 
 3505: #-- <del> tag (end tag required)
 3506: sub start_del {
 3507:     my ($target,$token) = @_;
 3508:     my $currentstring = '';
 3509:     if ($target eq 'web' || $target eq 'webgrade') {
 3510: 	$currentstring = $token->[4];     
 3511:     } 
 3512:     return $currentstring;
 3513: }
 3514: 
 3515: sub end_del {
 3516:     my ($target,$token) = @_;
 3517:     my $currentstring = '';
 3518:     if ($target eq 'web' || $target eq 'webgrade') {
 3519: 	$currentstring = $token->[2];    
 3520:     } 
 3521:     return $currentstring;
 3522: }
 3523: 
 3524: #-- <fieldset> tag (end tag required)
 3525: sub start_fieldset {
 3526:     my ($target,$token) = @_;
 3527:     my $currentstring = '';
 3528:     if ($target eq 'web' || $target eq 'webgrade') {
 3529: 	$currentstring = $token->[4];     
 3530:     } 
 3531:     return $currentstring;
 3532: }
 3533: 
 3534: sub end_fieldset {
 3535:     my ($target,$token) = @_;
 3536:     my $currentstring = '';
 3537:     if ($target eq 'web' || $target eq 'webgrade') {
 3538: 	$currentstring = $token->[2];    
 3539:     } 
 3540:     return $currentstring;
 3541: }
 3542: 
 3543: #-- <frame> tag (end tag forbidden)
 3544: sub start_frame {
 3545:     my ($target,$token) = @_;
 3546:     my $currentstring = '';
 3547:     if ($target eq 'web' || $target eq 'webgrade') {
 3548: 	$currentstring = $token->[4];     
 3549:     } 
 3550:     return $currentstring;
 3551: }
 3552: 
 3553: sub end_frame {
 3554:     my ($target,$token) = @_;
 3555:     my $currentstring = '';
 3556:     if ($target eq 'web' || $target eq 'webgrade') {
 3557: 	$currentstring = $token->[2];    
 3558:     } 
 3559:     return $currentstring;
 3560: }
 3561: 
 3562: #-- <iframe> tag (end tag required)
 3563: sub start_iframe {
 3564:     my ($target,$token) = @_;
 3565:     my $currentstring = '';
 3566:     if ($target eq 'web' || $target eq 'webgrade') {
 3567: 	$currentstring = $token->[4];     
 3568:     } 
 3569:     return $currentstring;
 3570: }
 3571: 
 3572: sub end_iframe {
 3573:     my ($target,$token) = @_;
 3574:     my $currentstring = '';
 3575:     if ($target eq 'web' || $target eq 'webgrade') {
 3576: 	$currentstring = $token->[2];    
 3577:     } 
 3578:     return $currentstring;
 3579: }
 3580: 
 3581: #-- <ins> tag (end tag required)
 3582: sub start_ins {
 3583:     my ($target,$token) = @_;
 3584:     my $currentstring = '';
 3585:     if ($target eq 'web' || $target eq 'webgrade') {
 3586: 	$currentstring = $token->[4];     
 3587:     } 
 3588:     return $currentstring;
 3589: }
 3590: 
 3591: sub end_ins {
 3592:     my ($target,$token) = @_;
 3593:     my $currentstring = '';
 3594:     if ($target eq 'web' || $target eq 'webgrade') {
 3595: 	$currentstring = $token->[2];    
 3596:     } 
 3597:     return $currentstring;
 3598: }
 3599: 
 3600: #-- <isindex> tag (end tag forbidden)
 3601: sub start_isindex {
 3602:     my ($target,$token) = @_;
 3603:     my $currentstring = '';
 3604:     if ($target eq 'web' || $target eq 'webgrade') {
 3605: 	$currentstring = $token->[4];     
 3606:     } 
 3607:     return $currentstring;
 3608: }
 3609: 
 3610: sub end_isindex {
 3611:     my ($target,$token) = @_;
 3612:     my $currentstring = '';
 3613:     if ($target eq 'web' || $target eq 'webgrade') {
 3614: 	$currentstring = $token->[2];    
 3615:     } 
 3616:     return $currentstring;
 3617: }
 3618: 
 3619: #-- <keygen> tag (end tag forbidden)
 3620: sub start_keygen {
 3621:     my ($target,$token) = @_;
 3622:     my $currentstring = '';
 3623:     if ($target eq 'web' || $target eq 'webgrade') {
 3624: 	$currentstring = $token->[4];     
 3625:     } 
 3626:     return $currentstring;
 3627: }
 3628: 
 3629: sub end_keygen {
 3630:     my ($target,$token) = @_;
 3631:     my $currentstring = '';
 3632:     if ($target eq 'web' || $target eq 'webgrade') {
 3633: 	$currentstring = $token->[2];    
 3634:     } 
 3635:     return $currentstring;
 3636: }
 3637: 
 3638: #-- <label> tag
 3639: sub start_label {
 3640:     my ($target,$token) = @_;
 3641:     my $currentstring = '';
 3642:     if ($target eq 'web' || $target eq 'webgrade') {
 3643: 	$currentstring = $token->[4];     
 3644:     } 
 3645:     return $currentstring;
 3646: }
 3647: 
 3648: sub end_label {
 3649:     my ($target,$token) = @_;
 3650:     my $currentstring = '';
 3651:     if ($target eq 'web' || $target eq 'webgrade') {
 3652: 	$currentstring = $token->[2];    
 3653:     } 
 3654:     return $currentstring;
 3655: }
 3656: 
 3657: #-- <layer> tag (end tag required)
 3658: sub start_layer {
 3659:     my ($target,$token) = @_;
 3660:     my $currentstring = '';
 3661:     if ($target eq 'web' || $target eq 'webgrade') {
 3662: 	$currentstring = $token->[4];     
 3663:     } 
 3664:     return $currentstring;
 3665: }
 3666: 
 3667: sub end_layer {
 3668:     my ($target,$token) = @_;
 3669:     my $currentstring = '';
 3670:     if ($target eq 'web' || $target eq 'webgrade') {
 3671: 	$currentstring = $token->[2];    
 3672:     } 
 3673:     return $currentstring;
 3674: }
 3675: 
 3676: #-- <legend> tag (end tag required)
 3677: sub start_legend {
 3678:     my ($target,$token) = @_;
 3679:     my $currentstring = '';
 3680:     if ($target eq 'web' || $target eq 'webgrade') {
 3681: 	$currentstring = $token->[4];     
 3682:     } 
 3683:     return $currentstring;
 3684: }
 3685: 
 3686: sub end_legend {
 3687:     my ($target,$token) = @_;
 3688:     my $currentstring = '';
 3689:     if ($target eq 'web' || $target eq 'webgrade') {
 3690: 	$currentstring = $token->[2];    
 3691:     } 
 3692:     return $currentstring;
 3693: }
 3694: 
 3695: #-- <link> tag (end tag forbidden)
 3696: sub start_link {
 3697:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
 3698:     my $currentstring = '';
 3699:     if ($target eq 'web' || $target eq 'webgrade') {
 3700: 	my $href=&Apache::lonxml::get_param('href',$parstack,$safeeval,
 3701: 					    undef,1);
 3702: 	&Apache::lonxml::extlink($href);
 3703: 	$currentstring = $token->[4];     
 3704:     } 
 3705:     return $currentstring;
 3706: }
 3707: 
 3708: sub end_link {
 3709:     my ($target,$token) = @_;
 3710:     my $currentstring = '';
 3711:     if ($target eq 'web' || $target eq 'webgrade') {
 3712: 	$currentstring = $token->[2];    
 3713:     } 
 3714:     return $currentstring;
 3715: }
 3716: 
 3717: #-- <marquee> tag (end tag optional)
 3718: sub start_marquee {
 3719:     my ($target,$token) = @_;
 3720:     my $currentstring = '';
 3721:     if ($target eq 'web' || $target eq 'webgrade') {
 3722: 	$currentstring = $token->[4];     
 3723:     } 
 3724:     return $currentstring;
 3725: }
 3726: 
 3727: sub end_marquee {
 3728:     my ($target,$token) = @_;
 3729:     my $currentstring = '';
 3730:     if ($target eq 'web' || $target eq 'webgrade') {
 3731: 	$currentstring = $token->[2];    
 3732:     } 
 3733:     return $currentstring;
 3734: }
 3735: 
 3736: #-- <multicol> tag (end tag required)
 3737: sub start_multicol {
 3738:     my ($target,$token) = @_;
 3739:     my $currentstring = &end_p();	# Close any pending <p>
 3740:     if ($target eq 'web' || $target eq 'webgrade') {
 3741: 	$currentstring .= $token->[4];     
 3742:     } 
 3743:     return $currentstring;
 3744: }
 3745: 
 3746: sub end_multicol {
 3747:     my ($target,$token) = @_;
 3748:     my $currentstring = '';
 3749:     if ($target eq 'web' || $target eq 'webgrade') {
 3750: 	$currentstring = $token->[2];    
 3751:     } 
 3752:     return $currentstring;
 3753: }
 3754: 
 3755: #-- <nobr> tag (end tag required)
 3756: sub start_nobr {
 3757:     my ($target,$token) = @_;
 3758:     my $currentstring = '';
 3759:     if ($target eq 'web' || $target eq 'webgrade') {
 3760: 	$currentstring = $token->[4];     
 3761:     }  elsif ($target eq 'tex') {
 3762: 	$currentstring='\mbox{';
 3763:     }
 3764:     return $currentstring;
 3765: }
 3766: 
 3767: sub end_nobr {
 3768:     my ($target,$token) = @_;
 3769:     my $currentstring = '';
 3770:     if ($target eq 'web' || $target eq 'webgrade') {
 3771: 	$currentstring = $token->[2];    
 3772:     }   elsif ($target eq 'tex') {
 3773: 	$currentstring='}';
 3774:     }
 3775:     return $currentstring;
 3776: }
 3777: 
 3778: #-- <noembed> tag (end tag required)
 3779: sub start_noembed {
 3780:     my ($target,$token) = @_;
 3781:     my $currentstring = '';
 3782:     if ($target eq 'web' || $target eq 'webgrade') {
 3783: 	$currentstring = $token->[4];     
 3784:     } 
 3785:     return $currentstring;
 3786: }
 3787: 
 3788: sub end_noembed {
 3789:     my ($target,$token) = @_;
 3790:     my $currentstring = '';
 3791:     if ($target eq 'web' || $target eq 'webgrade') {
 3792: 	$currentstring = $token->[2];    
 3793:     } 
 3794:     return $currentstring;
 3795: }
 3796: 
 3797: #-- <noframes> tag (end tag required)
 3798: sub start_noframes {
 3799:     my ($target,$token) = @_;
 3800:     my $currentstring = '';
 3801:     if ($target eq 'web' || $target eq 'webgrade') {
 3802: 	$currentstring = $token->[4];     
 3803:     } 
 3804:     return $currentstring;
 3805: }
 3806: 
 3807: sub end_noframes {
 3808:     my ($target,$token) = @_;
 3809:     my $currentstring = '';
 3810:     if ($target eq 'web' || $target eq 'webgrade') {
 3811: 	$currentstring = $token->[2];    
 3812:     } 
 3813:     return $currentstring;
 3814: }
 3815: 
 3816: #-- <nolayer> tag (end tag required)
 3817: sub start_nolayer {
 3818:     my ($target,$token) = @_;
 3819:     my $currentstring = '';
 3820:     if ($target eq 'web' || $target eq 'webgrade') {
 3821: 	$currentstring = $token->[4];     
 3822:     } 
 3823:     return $currentstring;
 3824: }
 3825: 
 3826: sub end_nolayer {
 3827:     my ($target,$token) = @_;
 3828:     my $currentstring = '';
 3829:     if ($target eq 'web' || $target eq 'webgrade') {
 3830: 	$currentstring = $token->[2];    
 3831:     } 
 3832:     return $currentstring;
 3833: }
 3834: 
 3835: #-- <noscript> tag (end tag required)
 3836: sub start_noscript {
 3837:     my ($target,$token) = @_;
 3838:     my $currentstring = '';
 3839:     if ($target eq 'web' || $target eq 'webgrade') {
 3840: 	$currentstring = $token->[4];     
 3841:     } 
 3842:     return $currentstring;
 3843: }
 3844: 
 3845: sub end_noscript {
 3846:     my ($target,$token) = @_;
 3847:     my $currentstring = '';
 3848:     if ($target eq 'web' || $target eq 'webgrade') {
 3849: 	$currentstring = $token->[2];    
 3850:     } 
 3851:     return $currentstring;
 3852: }
 3853: 
 3854: #-- <object> tag (end tag required)
 3855: sub start_object {
 3856:     my ($target,$token) = @_;
 3857:     my $currentstring = '';
 3858:     if ($target eq 'web' || $target eq 'webgrade') {
 3859: 	$currentstring = $token->[4];     
 3860:     } 
 3861:     return $currentstring;
 3862: }
 3863: 
 3864: sub end_object {
 3865:     my ($target,$token) = @_;
 3866:     my $currentstring = '';
 3867:     if ($target eq 'web' || $target eq 'webgrade') {
 3868: 	$currentstring = $token->[2];    
 3869:     } 
 3870:     return $currentstring;
 3871: }
 3872: 
 3873: #-- <optgroup> tag (end tag required)
 3874: sub start_optgroup {
 3875:     my ($target,$token) = @_;
 3876:     my $currentstring = '';
 3877:     if ($target eq 'web' || $target eq 'webgrade') {
 3878: 	$currentstring = $token->[4];     
 3879:     } 
 3880:     return $currentstring;
 3881: }
 3882: 
 3883: sub end_optgroup {
 3884:     my ($target,$token) = @_;
 3885:     my $currentstring = '';
 3886:     if ($target eq 'web' || $target eq 'webgrade') {
 3887: 	$currentstring = $token->[2];    
 3888:     } 
 3889:     return $currentstring;
 3890: }
 3891: 
 3892: #-- <samp> tag (end tag required)
 3893: sub start_samp {
 3894:     my ($target,$token) = @_;
 3895:     my $currentstring = '';
 3896:     if ($target eq 'web' || $target eq 'webgrade') {
 3897: 	$currentstring = $token->[4];     
 3898:     } elsif ($target eq 'tex') {
 3899: 	$currentstring='\texttt{';
 3900:     }
 3901:     return $currentstring;
 3902: }
 3903: 
 3904: sub end_samp {
 3905:     my ($target,$token) = @_;
 3906:     my $currentstring = '';
 3907:     if ($target eq 'web' || $target eq 'webgrade') {
 3908: 	$currentstring = $token->[2];    
 3909:     } elsif ($target eq 'tex') {
 3910: 	$currentstring='}';
 3911:     }
 3912:     return $currentstring;
 3913: }
 3914: 
 3915: #-- <server> tag
 3916: sub start_server {
 3917:     my ($target,$token) = @_;
 3918:     my $currentstring = '';
 3919:     if ($target eq 'web' || $target eq 'webgrade') {
 3920: 	$currentstring = $token->[4];     
 3921:     } 
 3922:     return $currentstring;
 3923: }
 3924: 
 3925: sub end_server {
 3926:     my ($target,$token) = @_;
 3927:     my $currentstring = '';
 3928:     if ($target eq 'web' || $target eq 'webgrade') {
 3929: 	$currentstring = $token->[2];    
 3930:     } 
 3931:     return $currentstring;
 3932: }
 3933: 
 3934: #-- <spacer> tag (end tag forbidden)
 3935: sub start_spacer {
 3936:     my ($target,$token) = @_;
 3937:     my $currentstring = &end_p();	# Close off any open <p> tag.
 3938:     if ($target eq 'web' || $target eq 'webgrade') {
 3939: 	$currentstring .= $token->[4];     
 3940:     } 
 3941:     return $currentstring;
 3942: }
 3943: 
 3944: sub end_spacer {
 3945:     my ($target,$token) = @_;
 3946:     my $currentstring = '';
 3947:     if ($target eq 'web' || $target eq 'webgrade') {
 3948: 	$currentstring = $token->[2];    
 3949:     } 
 3950:     return $currentstring;
 3951: }
 3952: 
 3953: #-- <span> tag (end tag required)
 3954: sub start_span {
 3955:     my ($target,$token) = @_;
 3956:     my $currentstring = '';
 3957:     if ($target eq 'web' || $target eq 'webgrade') {
 3958: 	$currentstring = $token->[4];     
 3959:     } 
 3960:     return $currentstring;
 3961: }
 3962: 
 3963: sub end_span {
 3964:     my ($target,$token) = @_;
 3965:     my $currentstring = '';
 3966:     if ($target eq 'web' || $target eq 'webgrade') {
 3967: 	$currentstring = $token->[2];    
 3968:     } 
 3969:     return $currentstring;
 3970: }
 3971: 
 3972: #-- <tbody> tag (end tag optional)
 3973: sub start_tbody {
 3974:     my ($target,$token) = @_;
 3975:     my $currentstring = '';
 3976:     if ($target eq 'web' || $target eq 'webgrade') {
 3977: 	$currentstring = $token->[4];     
 3978:     } 
 3979:     return $currentstring;
 3980: }
 3981: 
 3982: sub end_tbody {
 3983:     my ($target,$token) = @_;
 3984:     my $currentstring = '';
 3985:     if ($target eq 'web' || $target eq 'webgrade') {
 3986: 	$currentstring = $token->[2];    
 3987:     } 
 3988:     return $currentstring;
 3989: }
 3990: 
 3991: #-- <tfoot> tag (end tag optional)
 3992: sub start_tfoot {
 3993:     my ($target,$token) = @_;
 3994:     my $currentstring = '';
 3995:     if ($target eq 'web' || $target eq 'webgrade') {
 3996: 	$currentstring = $token->[4];     
 3997:     } 
 3998:     return $currentstring;
 3999: }
 4000: 
 4001: sub end_tfoot {
 4002:     my ($target,$token) = @_;
 4003:     my $currentstring = '';
 4004:     if ($target eq 'web' || $target eq 'webgrade') {
 4005: 	$currentstring = $token->[2];    
 4006:     } 
 4007:     return $currentstring;
 4008: }
 4009: 
 4010: #-- <thead> tag (end tag optional)
 4011: sub start_thead {
 4012:     my ($target,$token) = @_;
 4013:     my $currentstring = '';
 4014:     if ($target eq 'web' || $target eq 'webgrade') {
 4015: 	$currentstring = $token->[4];     
 4016:     } 
 4017:     return $currentstring;
 4018: }
 4019: 
 4020: sub end_thead {
 4021:     my ($target,$token) = @_;
 4022:     my $currentstring = '';
 4023:     if ($target eq 'web' || $target eq 'webgrade') {
 4024: 	$currentstring = $token->[2];    
 4025:     } 
 4026:     return $currentstring;
 4027: }
 4028: 
 4029: #-- <var> tag
 4030: sub start_var {
 4031:     my ($target,$token) = @_;
 4032:     my $currentstring = '';
 4033:     if ($target eq 'web' || $target eq 'webgrade') {
 4034: 	$currentstring = $token->[4];     
 4035:     } elsif ($target eq 'tex') {
 4036: 	$currentstring = '\textit{'; 
 4037:     }
 4038:     return $currentstring;
 4039: }
 4040: 
 4041: sub end_var {
 4042:     my ($target,$token) = @_;
 4043:     my $currentstring = '';
 4044:     if ($target eq 'web' || $target eq 'webgrade') {
 4045: 	$currentstring = $token->[2];
 4046:     } elsif ($target eq 'tex') {
 4047: 	$currentstring = '}'; 
 4048:     } 
 4049:     return $currentstring;
 4050: }
 4051: 
 4052: #-- <wbr> tag (end tag forbidden)
 4053: sub start_wbr {
 4054:     my ($target,$token) = @_;
 4055:     my $currentstring = '';
 4056:     if ($target eq 'web' || $target eq 'webgrade') {
 4057: 	$currentstring = $token->[4];     
 4058:     } 
 4059:     return $currentstring;
 4060: }
 4061: 
 4062: sub end_wbr {
 4063:     my ($target,$token) = @_;
 4064:     my $currentstring = '';
 4065:     if ($target eq 'web' || $target eq 'webgrade') {
 4066: 	$currentstring = $token->[2];    
 4067:     } 
 4068:     return $currentstring;
 4069: }
 4070: 
 4071: #-- <hideweboutput> tag
 4072: sub start_hideweboutput {
 4073:     my ($target,$token) = @_;
 4074:     if ($target eq 'web' || $target eq 'webgrade') {
 4075: 	&Apache::lonxml::startredirection();     
 4076:     } 
 4077:     return '';
 4078: }
 4079: 
 4080: sub end_hideweboutput {
 4081:     my ($target,$token) = @_;
 4082:     my $currentstring = '';
 4083:     if ($target eq 'web' || $target eq 'webgrade') {
 4084: 	$currentstring = &Apache::lonxml::endredirection();    
 4085:     } 
 4086:     return '';
 4087: }
 4088: 
 4089: 
 4090: sub image_replication {
 4091:     my $src = shift;
 4092:     if (not -e $src) { &Apache::lonnet::repcopy($src); }
 4093:     #replicates eps or ps 
 4094:     my $epssrc = my $pssrc = $src;
 4095:     $epssrc =~ s/\.(gif|jpg|jpeg|png)$/.eps/i;
 4096:     $pssrc  =~ s/\.(gif|jpg|jpeg|png)$/.ps/i;
 4097:     if (not -e $epssrc && not -e $pssrc) {
 4098: 	my $result=&Apache::lonnet::repcopy($epssrc);
 4099: 	if ($result ne 'ok') { &Apache::lonnet::repcopy($pssrc); }
 4100:     }
 4101:     return '';
 4102: }
 4103: #
 4104: #   Get correct sizing parameter for an image given
 4105: #   it's initial ht. and wid.  This allows sizing of
 4106: #   images that are generated on-the-fly (e.g. gnuplot)
 4107: #   as well as serving as a utility for image_size.
 4108: # 
 4109: #  Parameter:
 4110: #        height_param
 4111: #        width_param    - Initial picture dimensions.
 4112: #        scaling        - A scale factor.
 4113: #        parstack,      - the current stack of tag attributes 
 4114: #                         from the xml parser
 4115: #        safeeval,      - pointer to the safespace
 4116: #        depth,         - from what level in the stack to look for attributes
 4117: #                         (assumes -1 if unspecified)
 4118: #        cis            - look for attrubutes case insensitively
 4119: #                         (assumes false)
 4120: #
 4121: # Returns:
 4122: #   height, width   - new dimensions.
 4123: #
 4124: sub resize_image {
 4125:     my ($height_param, $width_param, $scaling,
 4126: 	$parstack, $safeeval, $depth, $cis) = @_;
 4127: 
 4128:     # First apply the scaling...
 4129: 
 4130:     $height_param = $height_param * $scaling;
 4131:     $width_param  = $width_param  * $scaling;
 4132: 
 4133:     #do we have any specified LaTeX size of the picture?
 4134:     my $toget='TeXwidth'; 
 4135:     if ($cis) { 
 4136: 	$toget=lc($toget); 
 4137:     }
 4138:     my $TeXwidth = &Apache::lonxml::get_param($toget,$parstack,
 4139: 					      $safeeval,$depth,$cis);
 4140:     $toget='TeXheight'; if ($cis) { $toget=lc($toget); }
 4141:     my $TeXheight = &Apache::lonxml::get_param($toget,$parstack,
 4142: 					       $safeeval,$depth,$cis);
 4143:     #do we have any specified web size of the picture?
 4144:     my $width = &Apache::lonxml::get_param('width',$parstack,$safeeval,
 4145: 					   $depth,1);
 4146:     if ($TeXwidth) { 
 4147: 	my $old_width_param=$width_param;
 4148: 	if ($TeXwidth=~/(\d+)\s*\%/) {
 4149: 	    $width_param = $1*$env{'form.textwidth'}/100;
 4150: 	} else { 
 4151: 	    $width_param = $TeXwidth;
 4152: 	}
 4153: 	if ($TeXheight) {
 4154: 	    $height_param = $TeXheight;
 4155: 	} elsif ($old_width_param) {
 4156: 	    $height_param=$TeXwidth/$old_width_param*$height_param;
 4157: 	}
 4158:     } elsif ($TeXheight) {
 4159: 	$height_param = $TeXheight;
 4160: 	if ($height_param) {
 4161: 	    $width_param  = $TeXheight/$height_param*$width_param;
 4162: 	}
 4163:     } elsif ($width) {
 4164: 	my $old_width_param=$width_param;
 4165: 	$width_param = $width*$scaling;
 4166: 	if ($old_width_param) {
 4167: 	    $height_param=$width_param/$old_width_param*$height_param;
 4168: 	}
 4169:     }
 4170:     if ($width_param > $env{'form.textwidth'}) {
 4171:         my $old_width_param=$width_param;
 4172: 	$width_param =0.95*$env{'form.textwidth'};
 4173: 	if ($old_width_param) {
 4174: 	    $height_param=$width_param/$old_width_param*$height_param;
 4175: 	}
 4176:     }
 4177: 
 4178:     return ($height_param, $width_param);
 4179: }
 4180: 
 4181: sub image_size {
 4182:     my ($src,$scaling,$parstack,$safeeval,$depth,$cis)=@_;
 4183: 
 4184:     #size of image from gif/jpg/jpeg/png 
 4185:     my $ressrc=&Apache::lonnet::filelocation($Apache::lonxml::pwd[-1],$src);
 4186:     if (-e $ressrc) {
 4187: 	$src = $ressrc;
 4188:     }
 4189:     my $image = Image::Magick->new;
 4190:     my $current_figure = $image->Read($src);
 4191:     my $width_param = $image->Get('width');
 4192:     my $height_param = $image->Get('height');
 4193:     &Apache::lonxml::debug("Image magick says: $src :  Height = $height_param width = $width_param");
 4194:     undef($image);
 4195: 
 4196:     ($height_param, $width_param) = &resize_image($height_param, $width_param,
 4197: 						  $scaling, $parstack, $safeeval, 
 4198: 						  $depth, $cis);
 4199: 
 4200:     return ($height_param, $width_param);
 4201: }
 4202: 
 4203: sub image_width {
 4204:     my ($height, $width) = &image_size(@_);
 4205:     return $width;
 4206: }
 4207: #  Not yet 100% sure this is correct in all circumstances..
 4208: #  due to my uncertainty about mods to image_size.
 4209: #
 4210: sub image_height {
 4211:     my ($height, $width) = &image_size(@_);
 4212:     return $height;
 4213: }
 4214: 
 4215: sub get_eps_image {
 4216:     my ($src)=@_;
 4217:     my $orig_src=&Apache::lonnet::filelocation($Apache::lonxml::pwd[-1], $src);
 4218: 
 4219:     # In order to prevent the substitution of the alt text, we need to
 4220:     # be sure the orig_src file is on system now so:
 4221: 
 4222:     if (! -e $orig_src) {
 4223: 	&Apache::lonnet::repcopy($orig_src); # Failure is not completely fatal.
 4224:     }
 4225:     &Apache::lonxml::debug("get_eps_image: Original image: $orig_src");
 4226:     my ($spath, $sname, $sext) = fileparse($src, qr/\.(gif|png|jpg|jpeg)/i);
 4227:     $src=~s/\.(gif|png|jpg|jpeg)$/\.eps/i;
 4228:     $src=&Apache::lonnet::filelocation($Apache::lonxml::pwd[-1],$src);
 4229:     &Apache::lonxml::debug("Filelocation gives: $src");
 4230:     if (! -e $src) {
 4231: 	&Apache::lonxml::debug("$src does not exist");
 4232: 	if (&Apache::lonnet::repcopy($src) ne 'ok' ) {
 4233: 	    &Apache::lonxml::debug("Repcopy of $src failed (1)");
 4234: 	    #if replication failed try to find ps file
 4235: 	    $src=~s/\.eps$/\.ps/;
 4236: 	    &Apache::lonxml::debug("Now looking for $src");
 4237: 	    #if no ps file try to replicate it.
 4238: 	    my $didrepcopy = &Apache::lonnet::repcopy($src);
 4239: 	    &Apache::lonxml::debug("repcopy of $src ... $didrepcopy");
 4240: 	    if ( (not -e $src) ||
 4241: 		($didrepcopy ne 'ok')) {
 4242: 		&Apache::lonxml::debug("Failed to find or replicate $src");
 4243: 
 4244: 		#if replication failed try to produce eps file dynamically
 4245: 		$src=~s/\.ps$/\.eps/;
 4246: 		my $temp_file;
 4247: 		open(FILE,">>/home/httpd/prtspool/$env{'user.name'}_$env{'user.domain'}_printout.dat");
 4248: 		my $newsrc=$orig_src;
 4249: 		$newsrc =~ s|(.*)/res/|/home/httpd/html/res/|;
 4250: 		&Apache::lonxml::debug("queueing $newsrc for dynamic eps production.");
 4251: 		print FILE "$newsrc\n";
 4252: 		close FILE;
 4253: 		$src=~s|/home/httpd/html/res|/home/httpd/prtspool|;
 4254: 		$src=~s|/home/([^/]*)/public_html/|/home/httpd/prtspool/$1/|;
 4255: 		if ($sext ne "") {	 # Put the ext. back in to uniquify.
 4256: 		    $src =~ s/\.eps$/$sext.eps/;
 4257: 		}
 4258: 	    }
 4259: 	}
 4260:     }
 4261:     my ($path,$file)=($src=~m|(.*)/([^/]*)$|);
 4262:     &Apache::lonxml::debug("get_eps_image returning: $path / $file<BR />");
 4263:     return ($path.'/',$file);
 4264: }
 4265: 
 4266: sub eps_generation {
 4267:     my ($src,$file,$width_param) = @_;	     
 4268:     my $filename = "/home/httpd/prtspool/$env{'user.name'}_$env{'user.domain'}_printout.dat";
 4269:     my $temp_file = Apache::File->new('>>'.$filename); 
 4270:     print $temp_file "$src\n";
 4271:     my $newsrc = $src;
 4272:     $newsrc =~ s/(\.gif|\.jpg|\.jpeg)$/\.eps/i;
 4273:     $newsrc=~s/\/home\/httpd\/html\/res//;
 4274:     $newsrc=~s/\/home\/([^\/]*)\/public_html\//\/$1\//;
 4275:     $newsrc=~s/\/\.\//\//;
 4276:     $newsrc=~s/\/([^\/]+)\.(ps|eps)/\//;
 4277:     if ($newsrc=~/\/home\/httpd\/lonUsers\//) {
 4278: 	$newsrc=~s/\/home\/httpd\/lonUsers//;
 4279: 	$newsrc=~s/\/([^\/]+)\/(\w)\/(\w)\/(\w)\//\/$1\//;
 4280:     }
 4281:     if ($newsrc=~/\/userfiles\//) {
 4282: 	return ' \graphicspath{{'.$newsrc.'}}\includegraphics[width='.$width_param.' mm]{'.$file.'} ';
 4283:     } else {
 4284: 	return ' \graphicspath{{/home/httpd/prtspool'.$newsrc.'}}\includegraphics[width='.$width_param.' mm]{'.$file.'} ';
 4285:     }
 4286: }
 4287: 
 4288: sub file_path {     
 4289:     my $src=shift;
 4290:     my ($file,$path); 
 4291:     if ($src =~ m!(.*)/([^/]*)$!) {
 4292: 	$file = $2; 
 4293: 	$path = $1.'/'; 
 4294:     } 
 4295:     return $file,$path;
 4296: }
 4297: #  Converts a measurement in to mm from any of 
 4298: #  the other valid LaTeX units of measure.
 4299: #  If the units of measure are missing from the 
 4300: #  parameter, it is assumed to be in and returned
 4301: #  with mm units of measure
 4302: sub recalc {
 4303:     my $argument = shift;
 4304:     if (not $argument=~/(mm|cm|in|pc|pt)/) {return $argument.' mm';}
 4305:     $argument=~/\s*(\d+\.?\d*)\s*(mm|cm|in|pc|pt)/;
 4306:     my $value=$1;
 4307:     my $units=$2;
 4308:     if ($units eq 'cm') {
 4309: 	$value*=10;
 4310:     } elsif ($units eq 'in') {
 4311: 	$value*=25.4;
 4312:     } elsif ($units eq 'pc') {
 4313: 	$value*=(25.4*12/72.27);
 4314:     } elsif ($units eq 'pt') {
 4315: 	$value*=(25.4/72.27);
 4316:     }
 4317:     return $value.' mm';
 4318: }
 4319: 
 4320: sub LATEX_length {
 4321:     my $garbage=shift;
 4322:     $garbage=~s/^\s+$//;
 4323:     $garbage=~s/^\s+(\S.*)/$1/;#space before 
 4324:     $garbage=~s/(.*\S)\s+$/$1/;#space after 
 4325:     $garbage=~s/(\s)+/$1/;#only one space
 4326:     $garbage=~s/(\\begin{([^\}]+)}|\\end{([^\}]+)})//g;#remove LaTeX \begin{...} and \end{...}
 4327:     $garbage=~s/(\$\_\{|\$\_|\$\^{|\$\^|\}\$)//g;#remove $_{,$_,$^{,$^,}$
 4328:     $garbage=~s/([^\\])\$/$1/g;#$
 4329:     $garbage=~s/(\\ensuremath\{\_\{|\\ensuremath\{\_|\\ensuremath\{\^{|\\ensuremath\{\^|\})//g;#remove \ensuremath{...}
 4330:    $garbage=~s/(\\alpha|\\beta|\\gamma|\\delta|\\epsilon|\\verepsilon|\\zeta|\\eta|\\theta|\\vartheta|\\iota|\\kappa|\\lambda|\\mu|\\nu|\\xi|\\pi|\\varpi|\\rho|\\varrho|\\sigma|\\varsigma|\\tau|\\upsilon|\\phi|\\varphi|\\chi|\\psi|\\omega|\\Gamma|\\Delta|\\Theta|\\Lambda|\\Xi|\\Pi|\\Sigma|\\Upsilon|\\Phi|\\Psi|\\Omega)/1/g;
 4331:     $garbage=~s/(\\pm|\\mp|\\times|\\div|\\cdot|\\ast|\\star|\\dagger|\\ddagger|\\amalg|\\cap|\\cup|\\uplus|\\sqcap|\\sqcup|\\vee|\\wedge|\\oplus|\\ominus|\\otimes|\\circ|\\bullet|\\diamond|\\lhd|\\rhd|\\unlhd|\\unrhd|\\oslash|\\odot|\\bigcirc|\\Box|\\Diamond|\\bigtriangleup|\\bigtriangledown|\\triangleleft|\\triangleright|\\setminus|\\wr)/1/g;
 4332:     $garbage=~s/(\\le|\\ll|\\leq|\\ge|\\geq|\\gg|\\neq|\\doreq|\\sim|\\simeq|\\subset|\\subseteq|\\sqsubset|\\sqsubseteq|\\in|\\vdash|\\models|\\supset|\\supseteq|\\sqsupset|\\sqsupseteq|\\ni|\\dash|\\perp|\\approx|\\cong|\\equiv|\\propto|\\prec|\\preceq|\\parallel|\\asymp|\\smile|\\frown|\\bowtie|\\succ|\\succeq|\\mid)/1/g;
 4333:     $garbage=~s/(\\not<|\\\\not\\le|\\not\\prec|\\not\\preceq|\\not\\subset|\\not\\subseteq|\\not\\sqsubseteq|\\not\\in|\\not>|\\not\\ge|\\not\\succ|\\notsucceq|\\not\\supset|\\notsupseteq|\\not\\sqsupseteq|\\notin|\\not=|\\not\\equiv|\\not\\sim|\\not\\simeq|\\not\\approx|\\not\\cong|\\not\\asymp)/1/g;
 4334:     $garbage=~s/(\\leftarrow|\\gets|\\Leftarrow|\\rightarrow|\\to|\\Rightarrow|\\leftrightarrow|\\Leftrightarrow|\\mapsto|\\hookleftarrow|\\leftharpoonup|\\leftkarpoondown|\\rightleftharpoons|\\longleftarrow|\\Longleftarrow|\\longrightarrow|\\Longrightarrow|\\longleftrightarrow|\\Longleftrightarrow|\\longmapsto|\\hookrightarrow|\\rightharpoonup|\\rightharpoondown|\\uparrow|\\Uparrow|\\downarrow|\\Downarrow|\\updownarrow|\\Updownarrow|\\nearrow|\\searrow|\\swarrow|\\nwarrow)/11/g;
 4335:     $garbage=~s/(\\aleph|\\hbar|\\imath|\\jmath|\\ell|\\wp|\\Re|\\Im|\\mho|\\prime|\\emptyset|\\nabla|\\surd|\\partial|\\top|\\bot|\\vdash|\\dashv|\\forall|\\exists|\\neg|\\flat|\\natural|\\sharp|\\\||\\angle|\\backslash|\\Box|\\Diamond|\\triangle|\\clubsuit|\\diamondsuit|\\heartsuit|\\spadesuit|\\Join|\\infty)/11/g;
 4336:     $garbage=~s/(\\hat{([^}]+)}|\\check{([^}]+)}|\\dot{([^}]+)}|\\breve{([^}]+)}|\\acute{([^}]+)}|\\ddot{([^}]+)}|\\grave{([^}]+)}|\\tilde{([^}]+)}|\\mathring{([^}]+)}|\\bar{([^}]+)}|\\vec{([^}]+)})/$1/g;
 4337:     #remove some other LaTeX command
 4338:     $garbage=~s|\\(\w+)\\|\\|g;	 
 4339:     $garbage=~s|\\(\w+)(\s*)|$2|g;	 	 
 4340:     $garbage=~s|\+|11|g;
 4341:     my  $value=length($garbage);
 4342:     return $value;
 4343: }
 4344: 
 4345: 
 4346: # is_inside_of $tagstack $tag
 4347: #    This sub returns true if the current state of Xml processing
 4348: #    is inside of the tag.   
 4349: # Parameters:
 4350: #     tagstack   - The tagstack from the parser.
 4351: #     tag        - The tag (without the <>'s.).
 4352: # Sample usage:
 4353: #     if (is_inside_of($tagstack "table")) {
 4354: #          # I'm in a table....
 4355: #      }
 4356: sub is_inside_of {
 4357:     my ($tagstack, $tag) = @_;
 4358:     my @stack = @$tagstack;
 4359:     for (my $i = ($#stack - 1); $i >= 0; $i--) {
 4360: 	if ($stack[$i] eq $tag) {
 4361: 	    return 1;
 4362: 	}
 4363:     }
 4364:     return 0;
 4365: }
 4366: 
 4367: 
 4368: 1;
 4369: __END__

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>