![]() ![]() | ![]() |
- backport lonplot.pm 1.91, lonxml.pm 1.281
1: # The LearningOnline Network with CAPA 2: # XML Parser Module 3: # 4: # $Id: lonxml.pm,v 1.266.2.2 2003/09/27 04:15:26 albertel Exp $ 5: # 6: # Copyright Michigan State University Board of Trustees 7: # 8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA). 9: # 10: # LON-CAPA is free software; you can redistribute it and/or modify 11: # it under the terms of the GNU General Public License as published by 12: # the Free Software Foundation; either version 2 of the License, or 13: # (at your option) any later version. 14: # 15: # LON-CAPA is distributed in the hope that it will be useful, 16: # but WITHOUT ANY WARRANTY; without even the implied warranty of 17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18: # GNU General Public License for more details. 19: # 20: # You should have received a copy of the GNU General Public License 21: # along with LON-CAPA; if not, write to the Free Software 22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23: # 24: # /home/httpd/html/adm/gpl.txt 25: # 26: # http://www.lon-capa.org/ 27: # 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: # last modified 06/26/00 by Alexander Sakharuk 40: # 11/6 Gerd Kortemeyer 41: # 6/1/1 Gerd Kortemeyer 42: # 2/21,3/13 Guy 43: # 3/29,5/4 Gerd Kortemeyer 44: # 5/26 Gerd Kortemeyer 45: # 5/27 H. K. Ng 46: # 6/2,6/3,6/8,6/9 Gerd Kortemeyer 47: # 6/12,6/13 H. K. Ng 48: # 6/16 Gerd Kortemeyer 49: # 7/27 H. K. Ng 50: # 8/7,8/9,8/10,8/11,8/15,8/16,8/17,8/18,8/20,8/23,8/24 Gerd Kortemeyer 51: # Guy Albertelli 52: # 9/26 Gerd Kortemeyer 53: # Dec Guy Albertelli 54: # YEAR=2002 55: # 1/1 Gerd Kortemeyer 56: # 1/2 Matthew Hall 57: # 1/3 Gerd Kortemeyer 58: # 59: 60: package Apache::lonxml; 61: use vars 62: qw(@pwd @outputstack $redirection $import @extlinks $metamode $evaluate %insertlist @namespace $prevent_entity_encode $errorcount $warningcount); 63: use strict; 64: use HTML::LCParser(); 65: use HTML::TreeBuilder(); 66: use HTML::Entities(); 67: use Safe(); 68: use Safe::Hole(); 69: use Math::Cephes(); 70: use Math::Random(); 71: use Opcode(); 72: 73: 74: sub register { 75: my ($space,@taglist) = @_; 76: foreach my $temptag (@taglist) { 77: push(@{ $Apache::lonxml::alltags{$temptag} },$space); 78: } 79: } 80: 81: sub deregister { 82: my ($space,@taglist) = @_; 83: foreach my $temptag (@taglist) { 84: my $tempspace = $Apache::lonxml::alltags{$temptag}[-1]; 85: if ($tempspace eq $space) { 86: pop(@{ $Apache::lonxml::alltags{$temptag} }); 87: } 88: } 89: #&printalltags(); 90: } 91: 92: use Apache::Constants qw(:common); 93: use Apache::lontexconvert(); 94: use Apache::style(); 95: use Apache::run(); 96: use Apache::londefdef(); 97: use Apache::scripttag(); 98: use Apache::edit(); 99: use Apache::inputtags(); 100: use Apache::outputtags(); 101: use Apache::lonnet(); 102: use Apache::File(); 103: use Apache::loncommon(); 104: use Apache::lonfeedback(); 105: use Apache::lonmsg(); 106: use Apache::loncacc(); 107: 108: #================================================== Main subroutine: xmlparse 109: #debugging control, to turn on debugging modify the correct handler 110: $Apache::lonxml::debug=0; 111: 112: # keeps count of the number of warnings and errors generated in a parse 113: $warningcount=0; 114: $errorcount=0; 115: 116: #path to the directory containing the file currently being processed 117: @pwd=(); 118: 119: #these two are used for capturing a subset of the output for later processing, 120: #don't touch them directly use &startredirection and &endredirection 121: @outputstack = (); 122: $redirection = 0; 123: 124: #controls wheter the <import> tag actually does 125: $import = 1; 126: @extlinks=(); 127: 128: # meta mode is a bit weird only some output is to be turned off 129: #<output> tag turns metamode off (defined in londefdef.pm) 130: $metamode = 0; 131: 132: # turns on and of run::evaluate actually derefencing var refs 133: $evaluate = 1; 134: 135: # data structure for eidt mode, determines what tags can go into what other tags 136: %insertlist=(); 137: 138: # stores the list of active tag namespaces 139: @namespace=(); 140: 141: # if 0 all high ASCII characters will be encoded into HTML Entities 142: $prevent_entity_encode=0; 143: 144: # has the dynamic menu been updated to know about this resource 145: $Apache::lonxml::registered=0; 146: 147: # a pointer the the Apache request object 148: $Apache::lonxml::request=''; 149: 150: # a problem number counter, and check on ether it is used 151: $Apache::lonxml::counter=1; 152: $Apache::lonxml::counter_changed=0; 153: 154: #internal check on whether to look at style defs 155: $Apache::lonxml::usestyle=1; 156: 157: #locations used to store the parameter string for style substitutions 158: $Apache::lonxml::style_values=''; 159: $Apache::lonxml::style_end_values=''; 160: 161: #array of ssi calls that need to occur after we are done parsing 162: @Apache::lonxml::ssi_info=(); 163: 164: sub xmlbegin { 165: my $output=''; 166: if ($ENV{'browser.mathml'}) { 167: $output='<?xml version="1.0"?>' 168: .'<?xml-stylesheet type="text/css" href="/adm/MathML/mathml.css"?>' 169: .'<!DOCTYPE html SYSTEM "/adm/MathML/mathml.dtd" ' 170: .'[<!ENTITY mathns "http://www.w3.org/1998/Math/MathML">]>' 171: .'<html xmlns:math="http://www.w3.org/1998/Math/MathML" ' 172: .'xmlns="http://www.w3.org/TR/REC-html40">'; 173: } else { 174: $output='<html>'; 175: } 176: return $output; 177: } 178: 179: sub xmlend { 180: my ($discussiononly,$symb)=@_; 181: my $discussion=''; 182: if ($ENV{'request.course.id'}) { 183: my $crs='/'.$ENV{'request.course.id'}; 184: if ($ENV{'request.course.sec'}) { 185: $crs.='_'.$ENV{'request.course.sec'}; 186: } 187: $crs=~s/\_/\//g; 188: my $seeid=&Apache::lonnet::allowed('rin',$crs); 189: unless ($symb) { 190: $symb=&Apache::lonnet::symbread(); 191: } 192: if ($symb) { 193: my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'}, 194: $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, 195: $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); 196: if ($contrib{'version'}) { 197: unless ($discussiononly) { 198: $discussion.= 199: '<address><hr />'; 200: } 201: my $idx; 202: for ($idx=1;$idx<=$contrib{'version'};$idx++) { 203: my $hidden=($contrib{'hidden'}=~/\.$idx\./); 204: my $deleted=($contrib{'deleted'}=~/\.$idx\./); 205: unless ((($hidden) && (!$seeid)) || ($deleted)) { 206: my $message=$contrib{$idx.':message'}; 207: $message=~s/\n/\<br \/\>/g; 208: $message=&Apache::lontexconvert::msgtexconverted($message); 209: if ($contrib{$idx.':attachmenturl'}) { 210: my ($fname,$ft) 211: =($contrib{$idx.':attachmenturl'}=~/\/(\w+)\.(\w+)$/); 212: $message.='<p>Attachment: <a href="'. 213: &Apache::lonnet::tokenwrapper($contrib{$idx.':attachmenturl'}). 214: '"><tt>'.$fname.'.'.$ft.'</tt></a>'; 215: } 216: if ($message) { 217: if ($hidden) { 218: $message='<font color="#888888">'.$message.'</font>'; 219: } 220: my $screenname=&Apache::loncommon::screenname( 221: $contrib{$idx.':sendername'}, 222: $contrib{$idx.':senderdomain'}); 223: my $plainname=&Apache::loncommon::nickname( 224: $contrib{$idx.':sendername'}, 225: $contrib{$idx.':senderdomain'}); 226: 227: my $sender='Anonymous'; 228: if ((!$contrib{$idx.':anonymous'}) || ($seeid)) { 229: $sender=&Apache::loncommon::aboutmewrapper( 230: $plainname, 231: $contrib{$idx.':sendername'}, 232: $contrib{$idx.':senderdomain'}).' ('. 233: $contrib{$idx.':sendername'}.' at '. 234: $contrib{$idx.':senderdomain'}.')'; 235: if ($contrib{$idx.':anonymous'}) { 236: $sender.=' [anonymous] '. 237: $screenname; 238: } 239: if ($seeid) { 240: if ($hidden) { 241: $sender.=' <a href="/adm/feedback?unhide='. 242: $symb.':::'.$idx.'">Make Visible</a>'; 243: } else { 244: $sender.=' <a href="/adm/feedback?hide='. 245: $symb.':::'.$idx.'">Hide</a>'; 246: } 247: $sender.=' <a href="/adm/feedback?deldisc='. 248: $symb.':::'.$idx.'">Delete</a>'; 249: } 250: } else { 251: if ($screenname) { 252: $sender='<i>'.$screenname.'</i>'; 253: } 254: } 255: $discussion.='<p><b>'.$sender.'</b> ('. 256: localtime($contrib{$idx.':timestamp'}). 257: '):<blockquote>'.$message. 258: '</blockquote></p>'; 259: } 260: } 261: } 262: unless ($discussiononly) { 263: $discussion.='</address>'; 264: } 265: } 266: if ($discussiononly) { 267: $discussion.=(<<ENDDISCUSS); 268: <form action="/adm/feedback" method="post" name="mailform" enctype="multipart/form-data"> 269: <input type="submit" name="discuss" value="Post Discussion" /> 270: <input type="submit" name="anondiscuss" value="Post Anonymous Discussion" /> 271: <input type="hidden" name="symb" value="$symb" /> 272: <input type="hidden" name="sendit" value="true" /> 273: <br /> 274: <font size="1">Note: in anonymous discussion, your name is visible only to 275: course faculty</font><br /> 276: <textarea name=comment cols=60 rows=10 wrap=hard></textarea> 277: <p> 278: Attachment (128 KB max size): <input type="file" name="attachment" /> 279: </p> 280: </form> 281: ENDDISCUSS 282: $discussion.=&Apache::lonfeedback::generate_preview_button(); 283: } 284: } 285: } 286: return $discussion.($discussiononly?'':'</html>'); 287: } 288: 289: sub tokeninputfield { 290: my $defhost=$Apache::lonnet::perlvar{'lonHostID'}; 291: $defhost=~tr/a-z/A-Z/; 292: return (<<ENDINPUTFIELD) 293: <script type="text/javascript"> 294: function updatetoken() { 295: var comp=new Array; 296: var barcode=unescape(document.tokeninput.barcode.value); 297: comp=barcode.split('*'); 298: if (typeof(comp[0])!="undefined") { 299: document.tokeninput.codeone.value=comp[0]; 300: } 301: if (typeof(comp[1])!="undefined") { 302: document.tokeninput.codetwo.value=comp[1]; 303: } 304: if (typeof(comp[2])!="undefined") { 305: comp[2]=comp[2].toUpperCase(); 306: document.tokeninput.codethree.value=comp[2]; 307: } 308: document.tokeninput.barcode.value=''; 309: } 310: </script> 311: <form method="post" name="tokeninput"> 312: <table border="2" bgcolor="#FFFFBB"> 313: <tr><th>DocID Checkin</th></tr> 314: <tr><td> 315: <table> 316: <tr> 317: <td>Scan in Barcode</td> 318: <td><input type="text" size="22" name="barcode" 319: onChange="updatetoken()"/></td> 320: </tr> 321: <tr><td><i>or</i> Type in DocID</td> 322: <td> 323: <input type="text" size="5" name="codeone" /> 324: <b><font size="+2">*</font></b> 325: <input type="text" size="5" name="codetwo" /> 326: <b><font size="+2">*</font></b> 327: <input type="text" size="10" name="codethree" value="$defhost" 328: onChange="this.value=this.value.toUpperCase()" /> 329: </td></tr> 330: </table> 331: </td></tr> 332: <tr><td><input type="submit" value="Check in DocID" /></td></tr> 333: </table> 334: </form> 335: ENDINPUTFIELD 336: } 337: 338: sub maketoken { 339: my ($symb,$tuname,$tudom,$tcrsid)=@_; 340: unless ($symb) { 341: $symb=&Apache::lonnet::symbread(); 342: } 343: unless ($tuname) { 344: $tuname=$ENV{'user.name'}; 345: $tudom=$ENV{'user.domain'}; 346: $tcrsid=$ENV{'request.course.id'}; 347: } 348: 349: return &Apache::lonnet::checkout($symb,$tuname,$tudom,$tcrsid); 350: } 351: 352: sub printtokenheader { 353: my ($target,$token,$tsymb,$tcrsid,$tudom,$tuname)=@_; 354: unless ($token) { return ''; } 355: 356: my ($symb,$courseid,$domain,$name) = &Apache::lonxml::whichuser(); 357: unless ($tsymb) { 358: $tsymb=$symb; 359: } 360: unless ($tuname) { 361: $tuname=$name; 362: $tudom=$domain; 363: $tcrsid=$courseid; 364: } 365: 366: my %reply=&Apache::lonnet::get('environment', 367: ['firstname','middlename','lastname','generation'], 368: $tudom,$tuname); 369: my $plainname=$reply{'firstname'}.' '. 370: $reply{'middlename'}.' '. 371: $reply{'lastname'}.' '. 372: $reply{'generation'}; 373: 374: if ($target eq 'web') { 375: my %idhash=&Apache::lonnet::idrget($tudom,($tuname)); 376: return 377: '<img align="right" src="/cgi-bin/barcode.png?encode='.$token.'" />'. 378: 'Checked out for '.$plainname. 379: '<br />User: '.$tuname.' at '.$tudom. 380: '<br />ID: '.$idhash{$tuname}. 381: '<br />CourseID: '.$tcrsid. 382: '<br />Course: '.$ENV{'course.'.$tcrsid.'.description'}. 383: '<br />DocID: '.$token. 384: '<br />Time: '.localtime().'<hr />'; 385: } else { 386: return $token; 387: } 388: } 389: 390: sub fontsettings() { 391: my $headerstring=''; 392: if (($ENV{'browser.os'} eq 'mac') && (!$ENV{'browser.mathml'})) { 393: $headerstring.= 394: '<meta Content-Type="text/html; charset=x-mac-roman">'; 395: } elsif (!$ENV{'browser.mathml'} && $ENV{'browser.unicode'}) { 396: $headerstring.= 397: '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />'; 398: } 399: return $headerstring; 400: } 401: 402: sub printalltags { 403: my $temp; 404: foreach $temp (sort keys %Apache::lonxml::alltags) { 405: &Apache::lonxml::debug("$temp -- ". 406: join(',',@{ $Apache::lonxml::alltags{$temp} })); 407: } 408: } 409: 410: sub xmlparse { 411: my ($request,$target,$content_file_string,$safeinit,%style_for_target) = @_; 412: 413: &setup_globals($request,$target); 414: &Apache::inputtags::initialize_inputtags(); 415: &Apache::outputtags::initialize_outputtags(); 416: &Apache::edit::initialize_edit(); 417: 418: # 419: # do we have a course style file? 420: # 421: 422: if ($ENV{'request.course.id'} && $ENV{'request.state'} ne 'construct') { 423: my $bodytext= 424: $ENV{'course.'.$ENV{'request.course.id'}.'.default_xml_style'}; 425: if ($bodytext) { 426: my $location=&Apache::lonnet::filelocation('',$bodytext); 427: my $styletext=&Apache::lonnet::getfile($location); 428: if ($styletext ne '-1') { 429: %style_for_target = (%style_for_target, 430: &Apache::style::styleparser($target,$styletext)); 431: } 432: } 433: } 434: #&printalltags(); 435: my @pars = (); 436: my $pwd=$ENV{'request.filename'}; 437: $pwd =~ s:/[^/]*$::; 438: &newparser(\@pars,\$content_file_string,$pwd); 439: 440: my $safeeval = new Safe; 441: my $safehole = new Safe::Hole; 442: &init_safespace($target,$safeeval,$safehole,$safeinit); 443: #-------------------- Redefinition of the target in the case of compound target 444: 445: ($target, my @tenta) = split('&&',$target); 446: 447: my @stack = (); 448: my @parstack = (); 449: &initdepth; 450: 451: my $finaloutput = &inner_xmlparse($target,\@stack,\@parstack,\@pars, 452: $safeeval,\%style_for_target); 453: 454: if ($ENV{'request.uri'}) { 455: &writeallows($ENV{'request.uri'}); 456: } 457: &do_registered_ssi(); 458: if ($Apache::lonxml::counter_changed) { &store_counter() } 459: return $finaloutput; 460: } 461: 462: sub htmlclean { 463: my ($raw,$full)=@_; 464: 465: my $tree = HTML::TreeBuilder->new; 466: $tree->ignore_unknown(0); 467: 468: $tree->parse($raw); 469: 470: my $output= $tree->as_HTML(undef,' '); 471: 472: $output=~s/\<(br|hr|img|meta|allow)(.*?)\>/\<$1$2 \/\>/gis; 473: $output=~s/\<\/(br|hr|img|meta|allow)\>//gis; 474: unless ($full) { 475: $output=~s/\<[\/]*(body|head|html)\>//gis; 476: } 477: 478: $tree = $tree->delete; 479: 480: return $output; 481: } 482: 483: sub latex_special_symbols { 484: my ($current_token,$stack,$parstack,$where)=@_; 485: if ($where eq 'header') { 486: $current_token =~ s/(\\|_|\^)/ /g; 487: $current_token =~ s/(\$|%|\#|&|\{|\})/\\$1/g; 488: } else { 489: $current_token=~s/\\ /\\char92 /g; 490: $current_token=~s/\^/\\char94 /g; 491: $current_token=~s/\~/\\char126 /g; 492: $current_token=~s/(&[^A-Za-z\#])/\\$1/g; 493: $current_token=~s/([^&])\#/$1\\#/g; 494: $current_token=~s/(\$|_|{|})/\\$1/g; 495: $current_token=~s/\\char92 /\\texttt{\\char92}/g; 496: $current_token=~s/(>|<)/\$$1\$/g; #more or less 497: if ($current_token=~m/\d%/) {$current_token =~ s/(\d)%/$1\\%/g;} #percent after digit 498: if ($current_token=~m/\s%/) {$current_token =~ s/(\s)%/$1\\%/g;} #persent after space 499: } 500: return $current_token; 501: } 502: 503: sub inner_xmlparse { 504: my ($target,$stack,$parstack,$pars,$safeeval,$style_for_target)=@_; 505: my $finaloutput = ''; 506: my $result; 507: my $token; 508: my $dontpop=0; 509: while ( $#$pars > -1 ) { 510: while ($token = $$pars['-1']->get_token) { 511: if (($token->[0] eq 'T') || ($token->[0] eq 'C') ) { 512: if ($metamode<1) { 513: my $text=$token->[1]; 514: if ($token->[0] eq 'C' && $target eq 'tex') { 515: $text = ''; 516: # $text = '%'.$text."\n"; 517: } 518: $result.=$text; 519: } 520: } elsif (($token->[0] eq 'D')) { 521: if ($metamode<1 && $target eq 'web') { 522: my $text=$token->[1]; 523: $result.=$text; 524: } 525: } elsif ($token->[0] eq 'PI') { 526: if ($metamode<1 && $target eq 'web') { 527: $result=$token->[2]; 528: } 529: } elsif ($token->[0] eq 'S') { 530: # add tag to stack 531: push (@$stack,$token->[1]); 532: # add parameters list to another stack 533: push (@$parstack,&parstring($token)); 534: &increasedepth($token); 535: if ($Apache::lonxml::usestyle && 536: exists($$style_for_target{$token->[1]})) { 537: $Apache::lonxml::usestyle=0; 538: my $string=$$style_for_target{$token->[1]}. 539: '<LONCAPA_INTERNAL_TURN_STYLE_ON />'; 540: &Apache::lonxml::newparser($pars,\$string); 541: $Apache::lonxml::style_values=$$parstack[-1]; 542: $Apache::lonxml::style_end_values=$$parstack[-1]; 543: } else { 544: $result = &callsub("start_$token->[1]", $target, $token, $stack, 545: $parstack, $pars, $safeeval, $style_for_target); 546: } 547: } elsif ($token->[0] eq 'E') { 548: if ($Apache::lonxml::usestyle && 549: exists($$style_for_target{'/'."$token->[1]"})) { 550: $Apache::lonxml::usestyle=0; 551: my $string=$$style_for_target{'/'.$token->[1]}. 552: '<LONCAPA_INTERNAL_TURN_STYLE_ON end="'.$token->[1].'" />'; 553: &Apache::lonxml::newparser($pars,\$string); 554: $Apache::lonxml::style_values=$Apache::lonxml::style_end_values; 555: $Apache::lonxml::style_end_values=''; 556: $dontpop=1; 557: } else { 558: #clear out any tags that didn't end 559: while ($token->[1] ne $$stack['-1'] && ($#$stack > -1)) { 560: my $lasttag=$$stack[-1]; 561: if ($token->[1] =~ /^$lasttag$/i) { 562: &Apache::lonxml::warning('Using tag </'.$token->[1].'> on line '.$token->[3].' as end tag to <'.$$stack[-1].'>'); 563: last; 564: } else { 565: &Apache::lonxml::warning('Found tag </'.$token->[1].'> on line '.$token->[3].' when looking for </'.$$stack[-1].'> in file'); 566: &end_tag($stack,$parstack,$token); 567: } 568: } 569: $result = &callsub("end_$token->[1]", $target, $token, $stack, 570: $parstack, $pars,$safeeval, $style_for_target); 571: } 572: } else { 573: &Apache::lonxml::error("Unknown token event :$token->[0]:$token->[1]:"); 574: } 575: #evaluate variable refs in result 576: if ($result ne "") { 577: my $extras; 578: if (!$Apache::lonxml::usestyle) { 579: $extras=$Apache::lonxml::style_values; 580: } 581: if ( $#$parstack > -1 ) { 582: $result=&Apache::run::evaluate($result,$safeeval,$extras.$$parstack[-1]); 583: } else { 584: $result= &Apache::run::evaluate($result,$safeeval,$extras); 585: } 586: } 587: if (($token->[0] eq 'T') || ($token->[0] eq 'C') || ($token->[0] eq 'D') ) { 588: #Style file definitions should be correct 589: if ($target eq 'tex' && ($Apache::lonxml::usestyle)) { 590: $result=&latex_special_symbols($result,$stack,$parstack); 591: } 592: } 593: 594: # Encode any high ASCII characters 595: if (!$Apache::lonxml::prevent_entity_encode) { 596: $result=&HTML::Entities::encode($result,"\200-\377"); 597: } 598: if ($Apache::lonxml::redirection) { 599: $Apache::lonxml::outputstack['-1'] .= $result; 600: } else { 601: $finaloutput.=$result; 602: } 603: $result = ''; 604: 605: if ($token->[0] eq 'E' && !$dontpop) { 606: &end_tag($stack,$parstack,$token); 607: } 608: $dontpop=0; 609: } 610: if ($#$pars > -1) { 611: pop @$pars; 612: pop @Apache::lonxml::pwd; 613: } 614: } 615: 616: # if ($target eq 'meta') { 617: # $finaloutput.=&endredirection; 618: # } 619: 620: 621: if (($ENV{'QUERY_STRING'}) && ($target eq 'web')) { 622: $finaloutput=&afterburn($finaloutput); 623: } 624: return $finaloutput; 625: } 626: 627: sub callsub { 628: my ($sub,$target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; 629: my $currentstring=''; 630: my $nodefault; 631: { 632: my $sub1; 633: no strict 'refs'; 634: my $tag=$token->[1]; 635: # get utterly rid of extended html tags 636: if ($tag=~/^x\-/i) { return ''; } 637: my $space=$Apache::lonxml::alltags{$tag}[-1]; 638: if (!$space) { 639: $tag=~tr/A-Z/a-z/; 640: $sub=~tr/A-Z/a-z/; 641: $space=$Apache::lonxml::alltags{$tag}[-1] 642: } 643: 644: my $deleted=0; 645: $Apache::lonxml::curdepth=join('_',@Apache::lonxml::depthcounter); 646: if (($token->[0] eq 'S') && ($target eq 'modified')) { 647: $deleted=&Apache::edit::handle_delete($space,$target,$token,$tagstack, 648: $parstack,$parser,$safeeval, 649: $style); 650: } 651: if (!$deleted) { 652: if ($space) { 653: #&Apache::lonxml::debug("Calling sub $sub in $space $metamode"); 654: $sub1="$space\:\:$sub"; 655: ($currentstring,$nodefault) = &$sub1($target,$token,$tagstack, 656: $parstack,$parser,$safeeval, 657: $style); 658: } else { 659: #&Apache::lonxml::debug("NOT Calling sub $sub in $space $metamode"); 660: if ($metamode <1) { 661: if (defined($token->[4]) && ($metamode < 1)) { 662: $currentstring = $token->[4]; 663: } else { 664: $currentstring = $token->[2]; 665: } 666: } 667: } 668: # &Apache::lonxml::debug("nodefalt:$nodefault:"); 669: if ($currentstring eq '' && $nodefault eq '') { 670: if ($target eq 'edit') { 671: #&Apache::lonxml::debug("doing default edit for $token->[1]"); 672: if ($token->[0] eq 'S') { 673: $currentstring = &Apache::edit::tag_start($target,$token); 674: } elsif ($token->[0] eq 'E') { 675: $currentstring = &Apache::edit::tag_end($target,$token); 676: } 677: } elsif ($target eq 'modified') { 678: if ($token->[0] eq 'S') { 679: $currentstring = $token->[4]; 680: $currentstring.=&Apache::edit::handle_insert(); 681: } elsif ($token->[0] eq 'E') { 682: $currentstring = $token->[2]; 683: $currentstring.=&Apache::edit::handle_insertafter($token->[1]); 684: } else { 685: $currentstring = $token->[2]; 686: } 687: } 688: } 689: } 690: use strict 'refs'; 691: } 692: return $currentstring; 693: } 694: 695: sub setup_globals { 696: my ($request,$target)=@_; 697: $Apache::lonxml::request=$request; 698: $Apache::lonxml::registered = 0; 699: $errorcount=0; 700: $warningcount=0; 701: $Apache::lonxml::default_homework_loaded=0; 702: $Apache::lonxml::usestyle=1; 703: &init_counter(); 704: @Apache::lonxml::pwd=(); 705: @Apache::lonxml::extlinks=(); 706: @Apache::lonxml::ssi_info=(); 707: if ($target eq 'meta') { 708: $Apache::lonxml::redirection = 0; 709: $Apache::lonxml::metamode = 1; 710: $Apache::lonxml::evaluate = 1; 711: $Apache::lonxml::import = 0; 712: } elsif ($target eq 'answer') { 713: $Apache::lonxml::redirection = 0; 714: $Apache::lonxml::metamode = 1; 715: $Apache::lonxml::evaluate = 1; 716: $Apache::lonxml::import = 1; 717: } elsif ($target eq 'grade') { 718: &startredirection; 719: $Apache::lonxml::metamode = 0; 720: $Apache::lonxml::evaluate = 1; 721: $Apache::lonxml::import = 1; 722: } elsif ($target eq 'modified') { 723: $Apache::lonxml::redirection = 0; 724: $Apache::lonxml::metamode = 0; 725: $Apache::lonxml::evaluate = 0; 726: $Apache::lonxml::import = 0; 727: } elsif ($target eq 'edit') { 728: $Apache::lonxml::redirection = 0; 729: $Apache::lonxml::metamode = 0; 730: $Apache::lonxml::evaluate = 0; 731: $Apache::lonxml::import = 0; 732: } elsif ($target eq 'analyze') { 733: $Apache::lonxml::redirection = 0; 734: $Apache::lonxml::metamode = 0; 735: $Apache::lonxml::evaluate = 1; 736: $Apache::lonxml::import = 1; 737: } else { 738: $Apache::lonxml::redirection = 0; 739: $Apache::lonxml::metamode = 0; 740: $Apache::lonxml::evaluate = 1; 741: $Apache::lonxml::import = 1; 742: } 743: } 744: 745: sub init_safespace { 746: my ($target,$safeeval,$safehole,$safeinit) = @_; 747: $safeeval->permit("entereval"); 748: $safeeval->permit(":base_math"); 749: $safeeval->permit("sort"); 750: $safeeval->deny(":base_io"); 751: $safehole->wrap(\&Apache::scripttag::xmlparse,$safeeval,'&xmlparse'); 752: $safehole->wrap(\&Apache::outputtags::multipart,$safeeval,'&multipart'); 753: $safehole->wrap(\&Apache::lonnet::EXT,$safeeval,'&EXT'); 754: 755: $safehole->wrap(\&Math::Cephes::asin,$safeeval,'&asin'); 756: $safehole->wrap(\&Math::Cephes::acos,$safeeval,'&acos'); 757: $safehole->wrap(\&Math::Cephes::atan,$safeeval,'&atan'); 758: $safehole->wrap(\&Math::Cephes::sinh,$safeeval,'&sinh'); 759: $safehole->wrap(\&Math::Cephes::cosh,$safeeval,'&cosh'); 760: $safehole->wrap(\&Math::Cephes::tanh,$safeeval,'&tanh'); 761: $safehole->wrap(\&Math::Cephes::asinh,$safeeval,'&asinh'); 762: $safehole->wrap(\&Math::Cephes::acosh,$safeeval,'&acosh'); 763: $safehole->wrap(\&Math::Cephes::atanh,$safeeval,'&atanh'); 764: $safehole->wrap(\&Math::Cephes::erf,$safeeval,'&erf'); 765: $safehole->wrap(\&Math::Cephes::erfc,$safeeval,'&erfc'); 766: $safehole->wrap(\&Math::Cephes::j0,$safeeval,'&j0'); 767: $safehole->wrap(\&Math::Cephes::j1,$safeeval,'&j1'); 768: $safehole->wrap(\&Math::Cephes::jn,$safeeval,'&jn'); 769: $safehole->wrap(\&Math::Cephes::jv,$safeeval,'&jv'); 770: $safehole->wrap(\&Math::Cephes::y0,$safeeval,'&y0'); 771: $safehole->wrap(\&Math::Cephes::y1,$safeeval,'&y1'); 772: $safehole->wrap(\&Math::Cephes::yn,$safeeval,'&yn'); 773: $safehole->wrap(\&Math::Cephes::yv,$safeeval,'&yv'); 774: 775: $safehole->wrap(\&Math::Cephes::bdtr ,$safeeval,'&bdtr' ); 776: $safehole->wrap(\&Math::Cephes::bdtrc ,$safeeval,'&bdtrc' ); 777: $safehole->wrap(\&Math::Cephes::bdtri ,$safeeval,'&bdtri' ); 778: $safehole->wrap(\&Math::Cephes::btdtr ,$safeeval,'&btdtr' ); 779: $safehole->wrap(\&Math::Cephes::chdtr ,$safeeval,'&chdtr' ); 780: $safehole->wrap(\&Math::Cephes::chdtrc,$safeeval,'&chdtrc'); 781: $safehole->wrap(\&Math::Cephes::chdtri,$safeeval,'&chdtri'); 782: $safehole->wrap(\&Math::Cephes::fdtr ,$safeeval,'&fdtr' ); 783: $safehole->wrap(\&Math::Cephes::fdtrc ,$safeeval,'&fdtrc' ); 784: $safehole->wrap(\&Math::Cephes::fdtri ,$safeeval,'&fdtri' ); 785: $safehole->wrap(\&Math::Cephes::gdtr ,$safeeval,'&gdtr' ); 786: $safehole->wrap(\&Math::Cephes::gdtrc ,$safeeval,'&gdtrc' ); 787: $safehole->wrap(\&Math::Cephes::nbdtr ,$safeeval,'&nbdtr' ); 788: $safehole->wrap(\&Math::Cephes::nbdtrc,$safeeval,'&nbdtrc'); 789: $safehole->wrap(\&Math::Cephes::nbdtri,$safeeval,'&nbdtri'); 790: $safehole->wrap(\&Math::Cephes::ndtr ,$safeeval,'&ndtr' ); 791: $safehole->wrap(\&Math::Cephes::ndtri ,$safeeval,'&ndtri' ); 792: $safehole->wrap(\&Math::Cephes::pdtr ,$safeeval,'&pdtr' ); 793: $safehole->wrap(\&Math::Cephes::pdtrc ,$safeeval,'&pdtrc' ); 794: $safehole->wrap(\&Math::Cephes::pdtri ,$safeeval,'&pdtri' ); 795: $safehole->wrap(\&Math::Cephes::stdtr ,$safeeval,'&stdtr' ); 796: $safehole->wrap(\&Math::Cephes::stdtri,$safeeval,'&stdtri'); 797: 798: # $safehole->wrap(\&Math::Cephes::new_fract,$safeeval,'&new_fract'); 799: # $safehole->wrap(\&Math::Cephes::radd,$safeeval,'&radd'); 800: # $safehole->wrap(\&Math::Cephes::rsub,$safeeval,'&rsub'); 801: # $safehole->wrap(\&Math::Cephes::rmul,$safeeval,'&rmul'); 802: # $safehole->wrap(\&Math::Cephes::rdiv,$safeeval,'&rdiv'); 803: # $safehole->wrap(\&Math::Cephes::euclid,$safeeval,'&euclid'); 804: 805: $safehole->wrap(\&Math::Random::random_beta,$safeeval,'&math_random_beta'); 806: $safehole->wrap(\&Math::Random::random_chi_square,$safeeval,'&math_random_chi_square'); 807: $safehole->wrap(\&Math::Random::random_exponential,$safeeval,'&math_random_exponential'); 808: $safehole->wrap(\&Math::Random::random_f,$safeeval,'&math_random_f'); 809: $safehole->wrap(\&Math::Random::random_gamma,$safeeval,'&math_random_gamma'); 810: $safehole->wrap(\&Math::Random::random_multivariate_normal,$safeeval,'&math_random_multivariate_normal'); 811: $safehole->wrap(\&Math::Random::random_multinomial,$safeeval,'&math_random_multinomial'); 812: $safehole->wrap(\&Math::Random::random_noncentral_chi_square,$safeeval,'&math_random_noncentral_chi_square'); 813: $safehole->wrap(\&Math::Random::random_noncentral_f,$safeeval,'&math_random_noncentral_f'); 814: $safehole->wrap(\&Math::Random::random_normal,$safeeval,'&math_random_normal'); 815: $safehole->wrap(\&Math::Random::random_permutation,$safeeval,'&math_random_permutation'); 816: $safehole->wrap(\&Math::Random::random_permuted_index,$safeeval,'&math_random_permuted_index'); 817: $safehole->wrap(\&Math::Random::random_uniform,$safeeval,'&math_random_uniform'); 818: $safehole->wrap(\&Math::Random::random_poisson,$safeeval,'&math_random_poisson'); 819: $safehole->wrap(\&Math::Random::random_uniform_integer,$safeeval,'&math_random_uniform_integer'); 820: $safehole->wrap(\&Math::Random::random_negative_binomial,$safeeval,'&math_random_negative_binomial'); 821: $safehole->wrap(\&Math::Random::random_binomial,$safeeval,'&math_random_binomial'); 822: $safehole->wrap(\&Math::Random::random_seed_from_phrase,$safeeval,'&random_seed_from_phrase'); 823: $safehole->wrap(\&Math::Random::random_set_seed_from_phrase,$safeeval,'&random_set_seed_from_phrase'); 824: $safehole->wrap(\&Math::Random::random_get_seed,$safeeval,'&random_get_seed'); 825: $safehole->wrap(\&Math::Random::random_set_seed,$safeeval,'&random_set_seed'); 826: 827: #need to inspect this class of ops 828: # $safeeval->deny(":base_orig"); 829: $safeinit .= ';$external::target="'.$target.'";'; 830: my $rndseed; 831: my ($symb,$courseid,$domain,$name) = &Apache::lonxml::whichuser(); 832: $rndseed=&Apache::lonnet::rndseed($symb,$courseid,$domain,$name); 833: $safeinit .= ';$external::randomseed='.$rndseed.';'; 834: &Apache::lonxml::debug("Setting rndseed to $rndseed"); 835: &Apache::run::run($safeinit,$safeeval); 836: } 837: 838: sub default_homework_load { 839: my ($safeeval)=@_; 840: &Apache::lonxml::debug('Loading default_homework'); 841: my $default=&Apache::lonnet::getfile('/home/httpd/html/res/adm/includes/default_homework.lcpm'); 842: if ($default eq -1) { 843: &Apache::lonxml::error("<b>Unable to find <i>default_homework.lcpm</i></b>"); 844: } else { 845: &Apache::run::run($default,$safeeval); 846: $Apache::lonxml::default_homework_loaded=1; 847: } 848: } 849: 850: sub startredirection { 851: $Apache::lonxml::redirection++; 852: push (@Apache::lonxml::outputstack, ''); 853: } 854: 855: sub endredirection { 856: if (!$Apache::lonxml::redirection) { 857: &Apache::lonxml::error("Endredirection was called, before a startredirection, perhaps you have unbalanced tags. Some debuging information:".join ":",caller); 858: return ''; 859: } 860: $Apache::lonxml::redirection--; 861: pop @Apache::lonxml::outputstack; 862: } 863: 864: sub end_tag { 865: my ($tagstack,$parstack,$token)=@_; 866: pop(@$tagstack); 867: pop(@$parstack); 868: &decreasedepth($token); 869: } 870: 871: sub initdepth { 872: @Apache::lonxml::depthcounter=(); 873: $Apache::lonxml::depth=-1; 874: $Apache::lonxml::olddepth=-1; 875: } 876: 877: sub increasedepth { 878: my ($token) = @_; 879: $Apache::lonxml::depth++; 880: $Apache::lonxml::depthcounter[$Apache::lonxml::depth]++; 881: if ($Apache::lonxml::depthcounter[$Apache::lonxml::depth]==1) { 882: $Apache::lonxml::olddepth=$Apache::lonxml::depth; 883: } 884: my $curdepth=join('_',@Apache::lonxml::depthcounter); 885: &Apache::lonxml::debug("s $Apache::lonxml::depth : $Apache::lonxml::olddepth : $curdepth : $token->[1]\n"); 886: #print "<br />s $Apache::lonxml::depth : $Apache::lonxml::olddepth : $curdepth : $token->[1]\n"; 887: } 888: 889: sub decreasedepth { 890: my ($token) = @_; 891: $Apache::lonxml::depth--; 892: if ($Apache::lonxml::depth<$Apache::lonxml::olddepth-1) { 893: $#Apache::lonxml::depthcounter--; 894: $Apache::lonxml::olddepth=$Apache::lonxml::depth+1; 895: } 896: if ( $Apache::lonxml::depth < -1) { 897: &Apache::lonxml::warning("Missing tags, unable to properly run file."); 898: $Apache::lonxml::depth='-1'; 899: } 900: my $curdepth=join('_',@Apache::lonxml::depthcounter); 901: &Apache::lonxml::debug("e $Apache::lonxml::depth : $Apache::lonxml::olddepth : $token->[1] : $curdepth\n"); 902: #print "<br />e $Apache::lonxml::depth : $Apache::lonxml::olddepth : $token->[1] : $curdepth\n"; 903: } 904: 905: sub get_all_text_unbalanced { 906: #there is a copy of this in lonpublisher.pm 907: my($tag,$pars)= @_; 908: my $token; 909: my $result=''; 910: $tag='<'.$tag.'>'; 911: while ($token = $$pars[-1]->get_token) { 912: if (($token->[0] eq 'T')||($token->[0] eq 'C')||($token->[0] eq 'D')) { 913: $result.=$token->[1]; 914: } elsif ($token->[0] eq 'PI') { 915: $result.=$token->[2]; 916: } elsif ($token->[0] eq 'S') { 917: $result.=$token->[4]; 918: } elsif ($token->[0] eq 'E') { 919: $result.=$token->[2]; 920: } 921: if ($result =~ /(.*)\Q$tag\E(.*)/s) { 922: &Apache::lonxml::debug('Got a winner with leftovers ::'.$2); 923: &Apache::lonxml::debug('Result is :'.$1); 924: $result=$1; 925: my $redo=$tag.$2; 926: &Apache::lonxml::newparser($pars,\$redo); 927: last; 928: } 929: } 930: return $result 931: } 932: 933: sub increment_counter { 934: my ($increment) = @_; 935: if (defined($increment) && $increment gt 0) { 936: $Apache::lonxml::counter+=$increment; 937: } else { 938: $Apache::lonxml::counter++; 939: } 940: $Apache::lonxml::counter_changed=1; 941: } 942: 943: sub init_counter { 944: if (defined($ENV{'form.counter'})) { 945: $Apache::lonxml::counter=$ENV{'form.counter'}; 946: $Apache::lonxml::counter_changed=0; 947: } else { 948: $Apache::lonxml::counter=1; 949: $Apache::lonxml::counter_changed=1; 950: } 951: } 952: 953: sub store_counter { 954: &Apache::lonnet::appenv(('form.counter' => $Apache::lonxml::counter)); 955: return ''; 956: } 957: 958: sub get_all_text { 959: my($tag,$pars)= @_; 960: &Apache::lonxml::debug("Got a ".ref($pars)); 961: my $gotfullstack=1; 962: if (ref($pars) ne 'ARRAY') { 963: $gotfullstack=0; 964: $pars=[$pars]; 965: } 966: my $depth=0; 967: my $token; 968: my $result=''; 969: if ( $tag =~ m:^/: ) { 970: my $tag=substr($tag,1); 971: #&Apache::lonxml::debug("have:$tag:"); 972: my $top_empty=0; 973: while (($depth >=0) && ($#$pars > -1) && (!$top_empty)) { 974: while (($depth >=0) && ($token = $$pars[-1]->get_token)) { 975: #&Apache::lonxml::debug("e token:$token->[0]:$depth:$token->[1]:".$#$pars.":".$#Apache::lonxml::pwd); 976: if (($token->[0] eq 'T')||($token->[0] eq 'C')||($token->[0] eq 'D')) { 977: $result.=$token->[1]; 978: } elsif ($token->[0] eq 'PI') { 979: $result.=$token->[2]; 980: } elsif ($token->[0] eq 'S') { 981: if ($token->[1] =~ /^$tag$/i) { $depth++; } 982: $result.=$token->[4]; 983: } elsif ($token->[0] eq 'E') { 984: if ( $token->[1] =~ /^$tag$/i) { $depth--; } 985: #skip sending back the last end tag 986: if ($depth > -1) { $result.=$token->[2]; } else { 987: $$pars[-1]->unget_token($token); 988: } 989: } 990: } 991: if (($depth >=0) && ($#$pars == 0) ) { $top_empty=1; } 992: if (($depth >=0) && ($#$pars > 0) ) { 993: pop(@$pars); 994: pop(@Apache::lonxml::pwd); 995: } 996: } 997: if ($top_empty && $depth >= 0) { 998: #never found the end tag ran out of text, throw error send back blank 999: &error('Never found end tag for <'.$tag.'>'); 1000: if ($gotfullstack) { 1001: my $newstring='</'.$tag.'>'.$result; 1002: &Apache::lonxml::newparser($pars,\$newstring); 1003: } 1004: $result=''; 1005: } 1006: } else { 1007: while ($#$pars > -1) { 1008: while ($token = $$pars[-1]->get_token) { 1009: #&Apache::lonxml::debug("s token:$token->[0]:$depth:$token->[1]"); 1010: if (($token->[0] eq 'T')||($token->[0] eq 'C')|| 1011: ($token->[0] eq 'D')) { 1012: $result.=$token->[1]; 1013: } elsif ($token->[0] eq 'PI') { 1014: $result.=$token->[2]; 1015: } elsif ($token->[0] eq 'S') { 1016: if ( $token->[1] =~ /^$tag$/i) { 1017: $$pars[-1]->unget_token($token); last; 1018: } else { 1019: $result.=$token->[4]; 1020: } 1021: } elsif ($token->[0] eq 'E') { 1022: $result.=$token->[2]; 1023: } 1024: } 1025: if (($#$pars > 0) ) { 1026: pop(@$pars); 1027: pop(@Apache::lonxml::pwd); 1028: } else { last; } 1029: } 1030: } 1031: if ($result =~ m|<LONCAPA_INTERNAL_TURN_STYLE_ON />|) { 1032: $Apache::lonxml::usestyle=1; 1033: } 1034: #&Apache::lonxml::debug("Exit:$result:"); 1035: return $result 1036: } 1037: 1038: sub newparser { 1039: my ($parser,$contentref,$dir) = @_; 1040: push (@$parser,HTML::LCParser->new($contentref)); 1041: $$parser['-1']->xml_mode('1'); 1042: if ( $dir eq '' ) { 1043: push (@Apache::lonxml::pwd, $Apache::lonxml::pwd[$#Apache::lonxml::pwd]); 1044: } else { 1045: push (@Apache::lonxml::pwd, $dir); 1046: } 1047: } 1048: 1049: sub parstring { 1050: my ($token) = @_; 1051: my $temp=''; 1052: foreach (@{$token->[3]}) { 1053: unless ($_=~/\W/) { 1054: my $val=$token->[2]->{$_}; 1055: $val =~ s/([\%\@\\\"\'])/\\$1/g; 1056: #if ($val =~ m/^[\%\@]/) { $val="\\".$val; } 1057: $temp .= "my \$$_=\"$val\";" 1058: } 1059: } 1060: return $temp; 1061: } 1062: 1063: sub writeallows { 1064: unless ($#extlinks>=0) { return; } 1065: my $thisurl='/res/'.&Apache::lonnet::declutter(shift); 1066: if ($ENV{'httpref.'.$thisurl}) { 1067: $thisurl=$ENV{'httpref.'.$thisurl}; 1068: } 1069: my $thisdir=$thisurl; 1070: $thisdir=~s/\/[^\/]+$//; 1071: my %httpref=(); 1072: foreach (@extlinks) { 1073: $httpref{'httpref.'. 1074: &Apache::lonnet::hreflocation($thisdir,$_)}=$thisurl; 1075: } 1076: @extlinks=(); 1077: &Apache::lonnet::appenv(%httpref); 1078: } 1079: 1080: sub register_ssi { 1081: my ($url,%form)=@_; 1082: push (@Apache::lonxml::ssi_info,{'url'=>$url,'form'=>\%form}); 1083: return ''; 1084: } 1085: 1086: sub do_registered_ssi { 1087: foreach my $info (@Apache::lonxml::ssi_info) { 1088: my %form=%{ $info->{'form'}}; 1089: my $url=$info->{'url'}; 1090: &Apache::lonnet::ssi($url,%form); 1091: } 1092: } 1093: # 1094: # Afterburner handles anchors, highlights and links 1095: # 1096: sub afterburn { 1097: my $result=shift; 1098: &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, 1099: ['highlight','anchor','link']); 1100: if ($ENV{'form.highlight'}) { 1101: foreach (split(/\,/,$ENV{'form.highlight'})) { 1102: my $anchorname=$_; 1103: my $matchthis=$anchorname; 1104: $matchthis=~s/\_+/\\s\+/g; 1105: $result=~s/($matchthis)/\<font color=\"red\"\>$1\<\/font\>/gs; 1106: } 1107: } 1108: if ($ENV{'form.link'}) { 1109: foreach (split(/\,/,$ENV{'form.link'})) { 1110: my ($anchorname,$linkurl)=split(/\>/,$_); 1111: my $matchthis=$anchorname; 1112: $matchthis=~s/\_+/\\s\+/g; 1113: $result=~s/($matchthis)/\<a href=\"$linkurl\"\>$1\<\/a\>/gs; 1114: } 1115: } 1116: if ($ENV{'form.anchor'}) { 1117: my $anchorname=$ENV{'form.anchor'}; 1118: my $matchthis=$anchorname; 1119: $matchthis=~s/\_+/\\s\+/g; 1120: $result=~s/($matchthis)/\<a name=\"$anchorname\"\>$1\<\/a\>/s; 1121: $result.=(<<"ENDSCRIPT"); 1122: <script type="text/javascript"> 1123: document.location.hash='$anchorname'; 1124: </script> 1125: ENDSCRIPT 1126: } 1127: return $result; 1128: } 1129: 1130: sub storefile { 1131: my ($file,$contents)=@_; 1132: if (my $fh=Apache::File->new('>'.$file)) { 1133: print $fh $contents; 1134: $fh->close(); 1135: } else { 1136: &warning("Unable to save file $file"); 1137: } 1138: } 1139: 1140: sub createnewhtml { 1141: my $filecontents=(<<SIMPLECONTENT); 1142: <html> 1143: <head> 1144: <title> 1145: Title of Document Goes Here 1146: </title> 1147: </head> 1148: <body bgcolor="#FFFFFF"> 1149: 1150: Body of Document Goes Here 1151: 1152: </body> 1153: </html> 1154: SIMPLECONTENT 1155: return $filecontents; 1156: } 1157: 1158: 1159: sub inserteditinfo { 1160: my ($result,$filecontents)=@_; 1161: $filecontents = &HTML::Entities::encode($filecontents); 1162: # my $editheader='<a href="#editsection">Edit below</a><hr />'; 1163: my $xml_help = Apache::loncommon::helpLatexCheatsheet(); 1164: my $titledisplay=&display_title(); 1165: my $buttons=(<<BUTTONS); 1166: <input type="submit" name="attemptclean" 1167: value="Save and then attempt to clean HTML" /> 1168: <input type="submit" name="savethisfile" value="Save this" /> 1169: <input type="submit" name="viewmode" value="View" /> 1170: BUTTONS 1171: my $editfooter=(<<ENDFOOTER); 1172: <hr /> 1173: <a name="editsection" /> 1174: <form method="post"> 1175: $xml_help 1176: <input type="hidden" name="editmode" value="Edit" /> 1177: $buttons<br /> 1178: <textarea cols="80" rows="40" name="filecont">$filecontents</textarea> 1179: <br />$buttons 1180: <br /> 1181: </form> 1182: $titledisplay 1183: ENDFOOTER 1184: # $result=~s/(\<body[^\>]*\>)/$1$editheader/is; 1185: $result=~s/(\<\/body\>)/$editfooter/is; 1186: return $result; 1187: } 1188: 1189: sub get_target { 1190: my $viewgrades=&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'}); 1191: if ( $ENV{'request.state'} eq 'published') { 1192: if ( defined($ENV{'form.grade_target'}) 1193: && ($viewgrades == 'F' )) { 1194: return ($ENV{'form.grade_target'}); 1195: } elsif (defined($ENV{'form.grade_target'})) { 1196: if (($ENV{'form.grade_target'} eq 'web') || 1197: ($ENV{'form.grade_target'} eq 'tex') ) { 1198: return $ENV{'form.grade_target'} 1199: } else { 1200: return 'web'; 1201: } 1202: } else { 1203: return 'web'; 1204: } 1205: } elsif ($ENV{'request.state'} eq 'construct') { 1206: if ( defined($ENV{'form.grade_target'})) { 1207: return ($ENV{'form.grade_target'}); 1208: } else { 1209: return 'web'; 1210: } 1211: } else { 1212: return 'web'; 1213: } 1214: } 1215: 1216: sub handler { 1217: my $request=shift; 1218: 1219: my $target=&get_target(); 1220: 1221: $Apache::lonxml::debug=$ENV{'user.debug'}; 1222: 1223: if ($ENV{'browser.mathml'}) { 1224: $request->content_type('text/xml'); 1225: } else { 1226: $request->content_type('text/html'); 1227: } 1228: &Apache::loncommon::no_cache($request); 1229: $request->send_http_header; 1230: 1231: return OK if $request->header_only; 1232: 1233: 1234: my $file=&Apache::lonnet::filelocation("",$request->uri); 1235: # 1236: # Edit action? Save file. 1237: # 1238: unless ($ENV{'request.state'} eq 'published') { 1239: if (($ENV{'form.savethisfile'}) || ($ENV{'form.attemptclean'})) { 1240: &storefile($file,$ENV{'form.filecont'}); 1241: } 1242: } 1243: my %mystyle; 1244: my $result = ''; 1245: my $filecontents=&Apache::lonnet::getfile($file); 1246: if ($filecontents eq -1) { 1247: $result=(<<ENDNOTFOUND); 1248: <html> 1249: <head> 1250: <title>File not found</title> 1251: </head> 1252: <body bgcolor="#FFFFFF"> 1253: <b>File not found: $file</b> 1254: </body> 1255: </html> 1256: ENDNOTFOUND 1257: $filecontents=''; 1258: if ($ENV{'request.state'} ne 'published') { 1259: $filecontents=&createnewhtml(); 1260: $ENV{'form.editmode'}='Edit'; #force edit mode 1261: } 1262: } else { 1263: unless ($ENV{'request.state'} eq 'published') { 1264: if ($ENV{'form.attemptclean'}) { 1265: $filecontents=&htmlclean($filecontents,1); 1266: } 1267: # 1268: # we are in construction space, see if edit mode forced 1269: &Apache::loncommon::get_unprocessed_cgi 1270: ($ENV{'QUERY_STRING'},['editmode']); 1271: } 1272: if (!$ENV{'form.editmode'} || $ENV{'form.viewmode'}) { 1273: $result = &Apache::lonxml::xmlparse($request,$target,$filecontents, 1274: '',%mystyle); 1275: } 1276: } 1277: 1278: # 1279: # Edit action? Insert editing commands 1280: # 1281: unless ($ENV{'request.state'} eq 'published') { 1282: if ($ENV{'form.editmode'} && (!($ENV{'form.viewmode'}))) { 1283: my $displayfile=$request->uri; 1284: $displayfile=~s/^\/[^\/]*//; 1285: $result='<html><body bgcolor="#FFFFFF"><h3>'.$displayfile. 1286: '</h3></body></html>'; 1287: $result=&inserteditinfo($result,$filecontents); 1288: } 1289: } 1290: 1291: writeallows($request->uri); 1292: 1293: 1294: $request->print($result); 1295: 1296: return OK; 1297: } 1298: 1299: sub display_title { 1300: my $result; 1301: if ($ENV{'request.state'} eq 'construct') { 1302: my $title=&Apache::lonnet::gettitle(); 1303: if (!defined($title) || $title eq '') { 1304: $title = $ENV{'request.filename'}; 1305: $title = substr($title, rindex($title, '/') + 1); 1306: } 1307: $result = "<script type='text/javascript'>top.document.title = '$title - LON-CAPA Construction Space';</script>"; 1308: } 1309: return $result; 1310: } 1311: 1312: sub debug { 1313: if ($Apache::lonxml::debug eq 1) { 1314: $|=1; 1315: print('<font size="-2"<pre>DEBUG:'.&HTML::Entities::encode($_[0])."</pre></font>\n"); 1316: } 1317: } 1318: 1319: sub error { 1320: $errorcount++; 1321: if (($Apache::lonxml::debug eq 1) || ($ENV{'request.state'} eq 'construct') ) { 1322: # If printing in construction space, put the error inside <pre></pre> 1323: print "<b>ERROR:</b>".join("\n",@_)."\n"; 1324: } else { 1325: print "<b>An Error occured while processing this resource. The instructor has been notified.</b> <br />"; 1326: #notify author 1327: &Apache::lonmsg::author_res_msg($ENV{'request.filename'},join('<br />',@_)); 1328: #notify course 1329: if ( $ENV{'request.course.id'} ) { 1330: my (undef,%users)=&Apache::lonfeedback::decide_receiver(undef,0,1,1,1); 1331: my $declutter=&Apache::lonnet::declutter($ENV{'request.filename'}); 1332: foreach (keys %users) { 1333: my ($user,$domain) = split(/:/, $_); 1334: &Apache::lonmsg::user_normal_msg($user,$domain, 1335: "Error [$declutter]",join('<br />',@_)); 1336: } 1337: } 1338: 1339: #FIXME probably shouldn't have me get everything forever. 1340: &Apache::lonmsg::user_normal_msg('albertel','msu',"Error in $ENV{'request.filename'}",join('<br />',@_)); 1341: #&Apache::lonmsg::user_normal_msg('albertel','103',"Error in $ENV{'request.filename'}",$_[0]); 1342: } 1343: } 1344: 1345: sub warning { 1346: $warningcount++; 1347: 1348: if ($ENV{'form.grade_target'} ne 'tex') { 1349: if ($ENV{'request.state'} eq 'construct' || $Apache::lonxml::debug) { 1350: print "<b>W</b>ARNING<b>:</b>".join('<br />',@_)."<br />\n"; 1351: } 1352: } 1353: } 1354: 1355: sub get_param { 1356: my ($param,$parstack,$safeeval,$context,$case_insensitive) = @_; 1357: if ( ! $context ) { $context = -1; } 1358: my $args =''; 1359: if ( $#$parstack > (-2-$context) ) { $args=$$parstack[$context]; } 1360: if ( ! $args ) { return undef; } 1361: if ( $case_insensitive ) { 1362: if ($args =~ s/(my \$)(\Q$param\E)(=\")/$1.lc($2).$3/ei) { 1363: return &Apache::run::run("{$args;".'return $'.$param.'}', 1364: $safeeval); #' 1365: } else { 1366: return undef; 1367: } 1368: } else { 1369: if ( $args =~ /my \$\Q$param\E=\"/ ) { 1370: return &Apache::run::run("{$args;".'return $'.$param.'}', 1371: $safeeval); #' 1372: } else { 1373: return undef; 1374: } 1375: } 1376: } 1377: 1378: sub get_param_var { 1379: my ($param,$parstack,$safeeval,$context,$case_insensitive) = @_; 1380: if ( ! $context ) { $context = -1; } 1381: my $args =''; 1382: if ( $#$parstack > (-2-$context) ) { $args=$$parstack[$context]; } 1383: &Apache::lonxml::debug("Args are $args param is $param"); 1384: if ($case_insensitive) { 1385: if (! ($args=~s/(my \$)(\Q$param\E)(=\")/$1.lc($2).$3/ei)) { 1386: return undef; 1387: } 1388: } elsif ( $args !~ /my \$\Q$param\E=\"/ ) { return undef; } 1389: my $value=&Apache::run::run("{$args;".'return $'.$param.'}',$safeeval); #' 1390: &Apache::lonxml::debug("first run is $value"); 1391: if ($value =~ /^[\$\@\%]\w+$/) { 1392: &Apache::lonxml::debug("doing second"); 1393: my @result=&Apache::run::run("return $value",$safeeval,1); 1394: if (!defined($result[0])) { 1395: return $value 1396: } else { 1397: if (wantarray) { return @result; } else { return $result[0]; } 1398: } 1399: } else { 1400: return $value; 1401: } 1402: } 1403: 1404: sub register_insert { 1405: my @data = split /\n/, &Apache::lonnet::getfile('/home/httpd/lonTabs/insertlist.tab'); 1406: my $i; 1407: my $tagnum=0; 1408: my @order; 1409: for ($i=0;$i < $#data; $i++) { 1410: my $line = $data[$i]; 1411: if ( $line =~ /^\#/ || $line =~ /^\s*\n/) { next; } 1412: if ( $line =~ /TABLE/ ) { last; } 1413: my ($tag,$descrip,$color,$function,$show) = split(/,/, $line); 1414: if ($tag) { 1415: $insertlist{"$tagnum.tag"} = $tag; 1416: $insertlist{"$tagnum.description"} = $descrip; 1417: $insertlist{"$tagnum.color"} = $color; 1418: $insertlist{"$tagnum.function"} = $function; 1419: if (!defined($show)) { $show='yes'; } 1420: $insertlist{"$tagnum.show"}= $show; 1421: $insertlist{"$tag.num"}=$tagnum; 1422: $tagnum++; 1423: } 1424: } 1425: $i++; #skipping TABLE line 1426: $tagnum = 0; 1427: for (;$i < $#data;$i++) { 1428: my $line = $data[$i]; 1429: my ($mnemonic,@which) = split(/ +/,$line); 1430: my $tag = $insertlist{"$tagnum.tag"}; 1431: for (my $j=0;$j <=$#which;$j++) { 1432: if ( $which[$j] eq 'Y' ) { 1433: if ($insertlist{"$j.show"} ne 'no') { 1434: push(@{ $insertlist{"$tag.which"} },$j); 1435: } 1436: } 1437: } 1438: $tagnum++; 1439: } 1440: } 1441: 1442: sub description { 1443: my ($token)=@_; 1444: my $tagnum; 1445: my $tag=$token->[1]; 1446: foreach my $namespace (reverse @Apache::lonxml::namespace) { 1447: my $testtag=$namespace.'::'.$tag; 1448: $tagnum=$insertlist{"$testtag.num"}; 1449: if (defined($tagnum)) { last; } 1450: } 1451: if (!defined ($tagnum)) { $tagnum=$Apache::lonxml::insertlist{"$tag.num"}; } 1452: return $insertlist{$tagnum.'.description'}; 1453: } 1454: 1455: # ----------------------------------------------------------------- whichuser 1456: # returns a list of $symb, $courseid, $domain, $name that is correct for 1457: # calls to lonnet functions for this setup. 1458: # - looks for form.grade_ parameters 1459: sub whichuser { 1460: my ($passedsymb)=@_; 1461: my ($symb,$courseid,$domain,$name,$publicuser); 1462: if (defined($ENV{'form.grade_symb'})) { 1463: my $tmp_courseid=$ENV{'form.grade_courseid'}; 1464: my $allowed=&Apache::lonnet::allowed('vgr',$tmp_courseid); 1465: if ($allowed) { 1466: $symb=$ENV{'form.grade_symb'}; 1467: $courseid=$ENV{'form.grade_courseid'}; 1468: $domain=$ENV{'form.grade_domain'}; 1469: $name=$ENV{'form.grade_username'}; 1470: } 1471: } else { 1472: if (!$passedsymb) { 1473: $symb=&Apache::lonnet::symbread(); 1474: } else { 1475: $symb=$passedsymb; 1476: } 1477: $courseid=$ENV{'request.course.id'}; 1478: $domain=$ENV{'user.domain'}; 1479: $name=$ENV{'user.name'}; 1480: if ($name eq 'public' && $domain eq 'public') { 1481: if (!defined($ENV{'form.username'})) { 1482: $ENV{'form.username'}.=time.rand(10000000); 1483: } 1484: $name.=$ENV{'form.username'}; 1485: } 1486: } 1487: return ($symb,$courseid,$domain,$name,$publicuser); 1488: } 1489: 1490: 1; 1491: __END__ 1492: 1493: