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