--- loncom/xml/lonxml.pm 2006/07/11 09:44:04 1.415 +++ loncom/xml/lonxml.pm 2007/04/07 00:04:40 1.442 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # XML Parser Module # -# $Id: lonxml.pm,v 1.415 2006/07/11 09:44:04 foxr Exp $ +# $Id: lonxml.pm,v 1.442 2007/04/07 00:04:40 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -88,6 +88,7 @@ use Apache::loncommon(); use Apache::lonfeedback(); use Apache::lonmsg(); use Apache::loncacc(); +use Apache::lonmaxima(); use Apache::lonlocal; #================================================== Main subroutine: xmlparse @@ -251,7 +252,7 @@ sub printtokenheader { my ($target,$token,$tsymb,$tcrsid,$tudom,$tuname)=@_; unless ($token) { return ''; } - my ($symb,$courseid,$domain,$name) = &Apache::lonxml::whichuser(); + my ($symb,$courseid,$domain,$name) = &Apache::lonnet::whichuser(); unless ($tsymb) { $tsymb=$symb; } @@ -342,6 +343,11 @@ sub xmlparse { my $finaloutput = &inner_xmlparse($target,\@stack,\@parstack,\@pars, $safeeval,\%style_for_target,1); + if (@stack) { + &warning("At end of file some tags were still left unclosed, ". + '<'.join('>, <',reverse(@stack)). + '>'); + } if ($env{'request.uri'}) { &writeallows($env{'request.uri'}); } @@ -544,7 +550,6 @@ sub callsub { } my $deleted=0; - $Apache::lonxml::curdepth=join('_',@Apache::lonxml::depthcounter); if (($token->[0] eq 'S') && ($target eq 'modified')) { $deleted=&Apache::edit::handle_delete($space,$target,$token,$tagstack, $parstack,$parser,$safeeval, @@ -580,17 +585,23 @@ sub callsub { } elsif ($token->[0] eq 'E') { $currentstring = &Apache::edit::tag_end($target,$token); } - } elsif ($target eq 'modified') { + } + } + if ($target eq 'modified' && $nodefault eq '') { + if ($currentstring eq '') { + if ($token->[0] eq 'S') { + $currentstring = $token->[4]; + } elsif ($token->[0] eq 'E') { + $currentstring = $token->[2]; + } else { + $currentstring = $token->[2]; + } + } if ($token->[0] eq 'S') { - $currentstring = $token->[4]; $currentstring.=&Apache::edit::handle_insert(); } elsif ($token->[0] eq 'E') { - $currentstring = $token->[2]; $currentstring.=&Apache::edit::handle_insertafter($token->[1]); - } else { - $currentstring = $token->[2]; } - } } } use strict 'refs'; @@ -669,6 +680,14 @@ sub init_safespace { '&chem_standard_order'); $safehole->wrap(\&Apache::response::check_status,$safeeval,'&check_status'); + $safehole->wrap(\&Apache::lonmaxima::maxima_eval,$safeeval,'&maxima_eval'); + $safehole->wrap(\&Apache::lonmaxima::maxima_check,$safeeval,'&maxima_check'); + $safehole->wrap(\&Apache::lonmaxima::maxima_cas_formula_fix,$safeeval, + '&maxima_cas_formula_fix'); + + $safehole->wrap(\&Apache::caparesponse::capa_formula_fix,$safeeval, + '&capa_formula_fix'); + $safehole->wrap(\&Math::Cephes::asin,$safeeval,'&asin'); $safehole->wrap(\&Math::Cephes::acos,$safeeval,'&acos'); $safehole->wrap(\&Math::Cephes::atan,$safeeval,'&atan'); @@ -772,8 +791,11 @@ sub init_safespace { $safehole->wrap(\&Math::Random::random_set_seed,$safeeval,'&random_set_seed'); $safehole->wrap(\&Apache::lonxml::error,$safeeval,'&LONCAPA_INTERNAL_ERROR'); $safehole->wrap(\&Apache::lonxml::debug,$safeeval,'&LONCAPA_INTERNAL_DEBUG'); + $safehole->wrap(\&Apache::lonnet::logthis,$safeeval,'&LONCAPA_INTERNAL_LOGTHIS'); + $safehole->wrap(\&Apache::inputtags::finalizeawards,$safeeval,'&LONCAPA_INTERNAL_FINALIZEAWARDS'); $safehole->wrap(\&Apache::caparesponse::get_sigrange,$safeeval,'&LONCAPA_INTERNAL_get_sigrange'); - +# use Data::Dumper; +# $safehole->wrap(\&Data::Dumper::Dumper,$safeeval,'&LONCAPA_INTERNAL_Dumper'); #need to inspect this class of ops # $safeeval->deny(":base_orig"); $safeeval->permit("require"); @@ -813,7 +835,7 @@ sub delete_package_recurse { sub initialize_rndseed { my ($safeeval)=@_; my $rndseed; - my ($symb,$courseid,$domain,$name) = &Apache::lonxml::whichuser(); + my ($symb,$courseid,$domain,$name) = &Apache::lonnet::whichuser(); $rndseed=&Apache::lonnet::rndseed($symb,$courseid,$domain,$name); my $safeinit = '$external::randomseed="'.$rndseed.'";'; &Apache::lonxml::debug("Setting rndseed to $rndseed"); @@ -885,51 +907,50 @@ sub end_tag { sub initdepth { @Apache::lonxml::depthcounter=(); - $Apache::lonxml::depth=-1; - $Apache::lonxml::olddepth=-1; + undef($Apache::lonxml::last_depth_count); } + my @timers; my $lasttime; +# @Apache::lonxml::depthcounter -> count of tags that exist so +# far at each level +# $Apache::lonxml::last_depth_count -> when ascending, need to +# remember the count for the level below the current level (for +# example going from 1_2 -> 1 -> 1_3 need to remember the 2 ) + sub increasedepth { my ($token) = @_; - $Apache::lonxml::depth++; - $Apache::lonxml::depthcounter[$Apache::lonxml::depth]++; - if ($Apache::lonxml::depthcounter[$Apache::lonxml::depth]==1) { - $Apache::lonxml::olddepth=$Apache::lonxml::depth; - } + push(@Apache::lonxml::depthcounter,$Apache::lonxml::last_depth_count+1); + undef($Apache::lonxml::last_depth_count); my $time; if ($Apache::lonxml::debug eq "1") { push(@timers,[&gettimeofday()]); $time=&tv_interval($lasttime); $lasttime=[&gettimeofday()]; } - my $spacing=' 'x($Apache::lonxml::depth-1); - my $curdepth=join('_',@Apache::lonxml::depthcounter); - &Apache::lonxml::debug("s$spacing$Apache::lonxml::depth : $Apache::lonxml::olddepth : $curdepth : $token->[1] : $time : \n"); + my $spacing=' 'x($#Apache::lonxml::depthcounter); + $Apache::lonxml::curdepth=join('_',@Apache::lonxml::depthcounter); +# &Apache::lonxml::debug("s$spacing$Apache::lonxml::depth : $Apache::lonxml::olddepth : $Apache::lonxml::curdepth : $token->[1] : $time"); #print "
s $Apache::lonxml::depth : $Apache::lonxml::olddepth : $curdepth : $token->[1]\n"; } sub decreasedepth { my ($token) = @_; - $Apache::lonxml::depth--; - if ($Apache::lonxml::depth<$Apache::lonxml::olddepth-1) { - $#Apache::lonxml::depthcounter--; - $Apache::lonxml::olddepth=$Apache::lonxml::depth+1; - } - if ( $Apache::lonxml::depth < -1) { - &Apache::lonxml::warning(&mt("Missing tags, unable to properly run file.")); - $Apache::lonxml::depth='-1'; + if ( $#Apache::lonxml::depthcounter == -1) { + &Apache::lonxml::warning(&mt("Missing tags, unable to properly run file.")); } + $Apache::lonxml::last_depth_count = pop(@Apache::lonxml::depthcounter); + my ($timer,$time); if ($Apache::lonxml::debug eq "1") { $timer=pop(@timers); $time=&tv_interval($lasttime); $lasttime=[&gettimeofday()]; } - my $spacing=' 'x$Apache::lonxml::depth; - my $curdepth=join('_',@Apache::lonxml::depthcounter); - &Apache::lonxml::debug("e$spacing$Apache::lonxml::depth : $Apache::lonxml::olddepth : $curdepth : $token->[1] : $time : ".&tv_interval($timer)."\n"); + my $spacing=' 'x($#Apache::lonxml::depthcounter); + $Apache::lonxml::curdepth = join('_',@Apache::lonxml::depthcounter); +# &Apache::lonxml::debug("e$spacing$Apache::lonxml::depth : $Apache::lonxml::olddepth : $Apache::lonxml::curdepth : $token->[1] : $time : ".&tv_interval($timer)); #print "
e $Apache::lonxml::depth : $Apache::lonxml::olddepth : $token->[1] : $curdepth\n"; } @@ -1014,7 +1035,7 @@ sub store_counter { } sub remember_problem_counter { - &Apache::lonnet::transfer_profile_to_env(); + &Apache::lonnet::transfer_profile_to_env(undef,undef,1); $state = $env{'form.counter'}; } @@ -1025,7 +1046,7 @@ sub store_counter { } sub get_problem_counter { if ($Apache::lonxml::counter_changed) { &store_counter() } - &Apache::lonnet::transfer_profile_to_env(); + &Apache::lonnet::transfer_profile_to_env(undef,undef,1); return $env{'form.counter'}; } } @@ -1149,19 +1170,23 @@ sub newparser { } sub parstring { - my ($token) = @_; - my $temp=''; - foreach (@{$token->[3]}) { - unless ($_=~/\W/) { - my $val=$token->[2]->{$_}; - $val =~ s/([\%\@\\\"\'])/\\$1/g; - $val =~ s/(\$[^{a-zA-Z_])/\\$1/g; - $val =~ s/(\$)$/\\$1/; - #if ($val =~ m/^[\%\@]/) { $val="\\".$val; } - $temp .= "my \$$_=\"$val\";"; - } - } - return $temp; + my ($token) = @_; + my (@vars,@values); + foreach my $attr (@{$token->[3]}) { + if ($attr!~/\W/) { + my $val=$token->[2]->{$attr}; + $val =~ s/([\%\@\\\"\'])/\\$1/g; + $val =~ s/(\$[^\{a-zA-Z_])/\\$1/g; + $val =~ s/(\$)$/\\$1/; + #if ($val =~ m/^[\%\@]/) { $val="\\".$val; } + push(@vars,"\$$attr"); + push(@values,"\"$val\""); + } + } + my $var_init = + (@vars) ? 'my ('.join(',',@vars).') = ('.join(',',@values).');' + : ''; + return $var_init; } sub extlink { @@ -1320,16 +1345,19 @@ FULLPAGE my $cleanbut = ''; my $titledisplay=&display_title(); - my %lt=&Apache::lonlocal::texthash('st' => 'Save this', - 'vi' => 'View', + my %lt=&Apache::lonlocal::texthash('st' => 'Save and Edit', + 'vi' => 'Save and View', + 'dv' => 'Discard Edits and View', + 'un' => 'undo', 'ed' => 'Edit'); my $buttons=(< +
BUTTONS $buttons.=&Apache::lonhtmlcommon::spelllink('xmledit','filecont'); - $buttons.=&Apache::lonhtmlcommon::htmlareaselectactive('filecont'); my $editfooter=(< @@ -1405,14 +1433,10 @@ sub handler { # # Edit action? Save file. # - unless ($env{'request.state'} eq 'published') { - if ($env{'form.savethisfile'}) { - if (&storefile($file,$env{'form.filecont'})) { - &Apache::lonxml::info("". - &mt('Updated').": ". - &Apache::lonlocal::locallocaltime(time). - " "); - } + if (!($env{'request.state'} eq 'published')) { + if ($env{'form.savethisfile'} || $env{'form.viewmode'} || $env{'form.Undo'}) { + my $html_file=&Apache::lonnet::getfile($file); + my $error = &Apache::lonhomework::handle_save_or_undo($request, \$html_file, \$env{'form.filecont'}); } } my %mystyle; @@ -1446,7 +1470,7 @@ ENDNOTFOUND &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['editmode']); } - if (!$env{'form.editmode'} || $env{'form.viewmode'}) { + if (!$env{'form.editmode'} || $env{'form.viewmode'} || $env{'form.discardview'}) { $result = &Apache::lonxml::xmlparse($request,$target,$filecontents, '',%mystyle); undef($Apache::lonhomework::parsing_a_task); @@ -1460,7 +1484,8 @@ ENDNOTFOUND # Edit action? Insert editing commands # unless ($env{'request.state'} eq 'published') { - if ($env{'form.editmode'} && (!($env{'form.viewmode'}))) { + if ($env{'form.editmode'} && (!($env{'form.viewmode'})) && (!($env{'form.discardview'}))) + { my $displayfile=$request->uri; $displayfile=~s/^\/[^\/]*//; my %options = (); @@ -1541,15 +1566,16 @@ sub error { $errormsg=&mt("An error occured while processing this resource. The author has been notified."); } my $host=$Apache::lonnet::perlvar{'lonHostID'}; - my $msg = join('
',(@_,"The occured on host $host")); + my $msg = join('
',(@_,"The error occurred on host $host")); #notify author &Apache::lonmsg::author_res_msg($env{'request.filename'},$msg); #notify course if ( $symb && $env{'request.course.id'} ) { my $cnum=$env{'course.'.$env{'request.course.id'}.'.num'}; my $cdom=$env{'course.'.$env{'request.course.id'}.'.domain'}; - my (undef,%users)=&Apache::lonfeedback::decide_receiver(undef,0,1,1,1); + my (undef,%users)=&Apache::lonmsg::decide_receiver(undef,0,1,1,1); my $declutter=&Apache::lonnet::declutter($env{'request.filename'}); + my $baseurl = &Apache::lonnet::clutter($declutter); my @userlist; foreach (keys %users) { my ($user,$domain) = split(/:/, $_); @@ -1560,8 +1586,11 @@ sub error { $cdom,$cnum); my $now=time; if ($now-$lastnotified{$key}>86400) { + my $title = &Apache::lonnet::gettitle($symb); + my $sentmessage; &Apache::lonmsg::user_normal_msg($user,$domain, - "Error [$declutter]",$msg); + "Error [$title]",$msg,'',$baseurl,'','', + \$sentmessage,$symb,$title,1); &Apache::lonnet::put('nohist_xmlerrornotifications', {$key => $now}, $cdom,$cnum); @@ -1624,14 +1653,14 @@ sub get_param { } if ( ! $args ) { return undef; } if ( $case_insensitive ) { - if ($args =~ s/(my \$)(\Q$param\E)(=\")/$1.lc($2).$3/ei) { + if ($args =~ s/(my (?:.*))(\$\Q$param\E[,\)])/$1.lc($2)/ei) { return &Apache::run::run("{$args;".'return $'.$param.'}', $safeeval); #' } else { return undef; } } else { - if ( $args =~ /my \$\Q$param\E=\"/ ) { + if ( $args =~ /my .*\$\Q$param\E[,\)]/ ) { return &Apache::run::run("{$args;".'return $'.$param.'}', $safeeval); #' } else { @@ -1650,10 +1679,10 @@ sub get_param_var { } &Apache::lonxml::debug("Args are $args param is $param"); if ($case_insensitive) { - if (! ($args=~s/(my \$)(\Q$param\E)(=\")/$1.lc($2).$3/ei)) { + if (! ($args=~s/(my (?:.*))(\$\Q$param\E[,\)])/$1.lc($2)/ei)) { return undef; } - } elsif ( $args !~ /my \$\Q$param\E=\"/ ) { return undef; } + } elsif ( $args !~ /my .*\$\Q$param\E[,\)]/ ) { return undef; } my $value=&Apache::run::run("{$args;".'return $'.$param.'}',$safeeval); #' &Apache::lonxml::debug("first run is $value"); if ($value =~ /^[\$\@\%][a-zA-Z_]\w*$/) { @@ -1669,7 +1698,7 @@ sub get_param_var { } } -sub register_insert { +sub register_insert_tab { my @data = split /\n/, &Apache::lonnet::getfile('/home/httpd/lonTabs/insertlist.tab'); my $i; my $tagnum=0; @@ -1681,13 +1710,13 @@ sub register_insert { my ($tag,$descrip,$color,$function,$show,$helpfile,$helpdesc) = split(/,/, $line); if ($tag) { $insertlist{"$tagnum.tag"} = $tag; - $insertlist{"$tagnum.description"} = $descrip; - $insertlist{"$tagnum.color"} = $color; - $insertlist{"$tagnum.function"} = $function; + $insertlist{"$tag.description"} = $descrip; + $insertlist{"$tag.color"} = $color; + $insertlist{"$tag.function"} = $function; if (!defined($show)) { $show='yes'; } - $insertlist{"$tagnum.show"}= $show; - $insertlist{"$tagnum.helpfile"} = $helpfile; - $insertlist{"$tagnum.helpdesc"} = $helpdesc; + $insertlist{"$tag.show"}= $show; + $insertlist{"$tag.helpfile"} = $helpfile; + $insertlist{"$tag.helpdesc"} = $helpdesc; $insertlist{"$tag.num"}=$tagnum; $tagnum++; } @@ -1701,7 +1730,7 @@ sub register_insert { for (my $j=0;$j <=$#which;$j++) { if ( $which[$j] eq 'Y' ) { if ($insertlist{"$j.show"} ne 'no') { - push(@{ $insertlist{"$tag.which"} },$j); + push(@{ $insertlist{"$tag.which"} },$insertlist{"$j.tag"}); } } } @@ -1709,73 +1738,145 @@ sub register_insert { } } +sub register_insert_xml { + my $parser = HTML::LCParser->new($Apache::lonnet::perlvar{'lonTabDir'} + .'/insertlist.xml'); + my ($tagnum,$in_help)=(0,0); + my @alltags; + my $tag; + while (my $token = $parser->get_token()) { + if ($token->[0] eq 'S') { + my $key; + if ($token->[1] eq 'tag') { + $tag = $token->[2]{'name'}; + $insertlist{"$tagnum.tag"} = $tag; + $insertlist{"$tag.num"} = $tagnum; + push(@alltags,$tag); + } elsif ($in_help && $token->[1] eq 'file') { + $key = $tag.'.helpfile'; + } elsif ($in_help && $token->[1] eq 'description') { + $key = $tag.'.helpdesc'; + } elsif ($token->[1] eq 'description' || + $token->[1] eq 'color' || + $token->[1] eq 'show' ) { + $key = $tag.'.'.$token->[1]; + } elsif ($token->[1] eq 'insert_sub') { + $key = $tag.'.function'; + } elsif ($token->[1] eq 'help') { + $in_help=1; + } elsif ($token->[1] eq 'allow') { + $key = $tag.'.allow'; + } + if (defined($key)) { + $insertlist{$key} = $parser->get_text(); + $insertlist{$key} =~ s/(^\s*|\s*$ )//gx; + } + } elsif ($token->[0] eq 'E') { + if ($token->[1] eq 'tag') { + undef($tag); + $tagnum++; + } elsif ($token->[1] eq 'help') { + undef($in_help); + } + } + } + + # parse the allows and ignore tags set to no + foreach my $tag (@alltags) { + my $allow = $insertlist{"$tag.allow"}; + foreach my $element (split(',',$allow)) { + $element =~ s/(^\s*|\s*$ )//gx; + if ($insertlist{"$element.show"} ne 'no') { + push(@{ $insertlist{$tag.'.which'} },$element); + } + } + } +} + +sub register_insert { +# ®ister_insert_tab(@_); +# &dump_insertlist('1'); +# undef(%insertlist); + return ®ister_insert_xml(@_); +# &dump_insertlist('2'); +} + +sub dump_insertlist { + my ($ext) = @_; + open(XML,">/tmp/insertlist.xml.$ext"); + print XML (""); + my $i=0; + + while (exists($insertlist{"$i.tag"})) { + my $tag = $insertlist{"$i.tag"}; + print XML (" +\t"); + if (defined($insertlist{"$tag.description"})) { + print XML (" +\t\t".$insertlist{"$tag.description"}.""); + } + if (defined($insertlist{"$tag.color"})) { + print XML (" +\t\t".$insertlist{"$tag.color"}.""); + } + if (defined($insertlist{"$tag.function"})) { + print XML (" +\t\t".$insertlist{"$tag.function"}.""); + } + if (defined($insertlist{"$tag.show"}) + && $insertlist{"$tag.show"} ne 'yes') { + print XML (" +\t\t".$insertlist{"$tag.show"}.""); + } + if (defined($insertlist{"$tag.helpfile"})) { + print XML (" +\t\t +\t\t\t".$insertlist{"$tag.helpfile"}.""); + if ($insertlist{"$tag.helpdesc"} ne '') { + print XML (" +\t\t\t".$insertlist{"$tag.helpdesc"}.""); + } + print XML (" +\t\t"); + } + if (defined($insertlist{"$tag.which"})) { + print XML (" +\t\t".join(',',sort(@{ $insertlist{"$tag.which"} })).""); + } + print XML (" +\t"); + $i++; + } + print XML ("\n\n"); + close(XML); +} + sub description { - my ($token)=@_; - my $tagnum; - my $tag=$token->[1]; - foreach my $namespace (reverse @Apache::lonxml::namespace) { - my $testtag=$namespace.'::'.$tag; - $tagnum=$insertlist{"$testtag.num"}; - if (defined($tagnum)) { last; } - } - if (!defined ($tagnum)) { $tagnum=$Apache::lonxml::insertlist{"$tag.num"}; } - return $insertlist{$tagnum.'.description'}; + my ($token)=@_; + my $tag = &get_tag($token); + return $insertlist{$tag.'.description'}; } # Returns a list containing the help file, and the description sub helpinfo { - my ($token)=@_; - my $tagnum; - my $tag=$token->[1]; - foreach my $namespace (reverse @Apache::lonxml::namespace) { - my $testtag=$namespace.'::'.$tag; - $tagnum=$insertlist{"$testtag.num"}; - if (defined($tagnum)) { last; } - } - if (!defined ($tagnum)) { $tagnum=$Apache::lonxml::insertlist{"$tag.num"}; } - return ($insertlist{$tagnum.'.helpfile'}, $insertlist{$tagnum.'.helpdesc'}); + my ($token)=@_; + my $tag = &get_tag($token); + return ($insertlist{$tag.'.helpfile'}, $insertlist{$tag.'.helpdesc'}); } -# ----------------------------------------------------------------- whichuser -# returns a list of $symb, $courseid, $domain, $name that is correct for -# calls to lonnet functions for this setup. -# - looks for form.grade_ parameters -sub whichuser { - my ($passedsymb)=@_; - my ($symb,$courseid,$domain,$name,$publicuser); - if (defined($env{'form.grade_symb'})) { - my ($tmp_courseid)= - &Apache::loncommon::get_env_multiple('form.grade_courseid'); - my $allowed=&Apache::lonnet::allowed('vgr',$tmp_courseid); - if (!$allowed && - exists($env{'request.course.sec'}) && - $env{'request.course.sec'} !~ /^\s*$/) { - $allowed=&Apache::lonnet::allowed('vgr',$tmp_courseid. - '/'.$env{'request.course.sec'}); - } - if ($allowed) { - ($symb)=&Apache::loncommon::get_env_multiple('form.grade_symb'); - $courseid=$tmp_courseid; - ($domain)=&Apache::loncommon::get_env_multiple('form.grade_domain'); - ($name)=&Apache::loncommon::get_env_multiple('form.grade_username'); - return ($symb,$courseid,$domain,$name,$publicuser); - } - } - if (!$passedsymb) { - $symb=&Apache::lonnet::symbread(); - } else { - $symb=$passedsymb; - } - $courseid=$env{'request.course.id'}; - $domain=$env{'user.domain'}; - $name=$env{'user.name'}; - if ($name eq 'public' && $domain eq 'public') { - if (!defined($env{'form.username'})) { - $env{'form.username'}.=time.rand(10000000); - } - $name.=$env{'form.username'}; - } - return ($symb,$courseid,$domain,$name,$publicuser); +sub get_tag { + my ($token)=@_; + my $tagnum; + my $tag=$token->[1]; + foreach my $namespace (reverse(@Apache::lonxml::namespace)) { + my $testtag = $namespace.'::'.$tag; + $tagnum = $insertlist{"$testtag.num"}; + last if (defined($tagnum)); + } + if (!defined($tagnum)) { + $tagnum = $Apache::lonxml::insertlist{"$tag.num"}; + } + return $insertlist{"$tagnum.tag"}; } 1;