--- loncom/xml/lonxml.pm	2004/05/27 04:25:13	1.319
+++ loncom/xml/lonxml.pm	2004/10/05 18:51:50	1.339
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # XML Parser Module 
 #
-# $Id: lonxml.pm,v 1.319 2004/05/27 04:25:13 albertel Exp $
+# $Id: lonxml.pm,v 1.339 2004/10/05 18:51:50 albertel Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -40,7 +40,7 @@
 
 package Apache::lonxml; 
 use vars 
-qw(@pwd @outputstack $redirection $import @extlinks $metamode $evaluate %insertlist @namespace $errorcount $warningcount);
+qw(@pwd @outputstack $redirection $import @extlinks $metamode $evaluate %insertlist @namespace $errorcount $warningcount @htmlareafields);
 use strict;
 use HTML::LCParser();
 use HTML::TreeBuilder();
@@ -51,7 +51,7 @@ use Math::Cephes();
 use Math::Random();
 use Opcode();
 use POSIX qw(strftime);
-
+use Time::HiRes qw( gettimeofday tv_interval );
 
 sub register {
   my ($space,@taglist) = @_;
@@ -150,6 +150,7 @@ $Apache::lonxml::warnings_error_header='
 
 sub xmlbegin {
   my $output='';
+  @htmlareafields=();
   if ($ENV{'browser.mathml'}) {
       $output='<?xml version="1.0"?>'
             .'<?xml-stylesheet type="text/css" href="/adm/MathML/mathml.css"?>'
@@ -164,13 +165,21 @@ sub xmlbegin {
 }
 
 sub xmlend {
+    my ($target,$parser)=@_;
     my $mode='xml';
     my $status='OPEN';
     if ($Apache::lonhomework::parsing_a_problem) {
 	$mode='problem';
 	$status=$Apache::inputtags::status[-1]; 
     }
-    return &Apache::lonfeedback::list_discussion($mode,$status).'</html>';
+    my $discussion=&Apache::lonfeedback::list_discussion($mode,$status);    
+    if ($target eq 'tex') {
+	$discussion.='<tex>\keephidden{ENDOFPROBLEM}\vskip 0.5mm\noindent\makebox[\textwidth/$number_of_columns][b]{\hrulefill}\end{document}</tex>';
+	&Apache::lonxml::newparser($parser,\$discussion,'');
+	return '';
+    } else {
+	return $discussion.'</html>';
+    }
 }
 
 sub tokeninputfield {
@@ -311,13 +320,15 @@ sub xmlparse {
      my $bodytext=
 	 $ENV{'course.'.$ENV{'request.course.id'}.'.default_xml_style'};
      if ($bodytext) {
-       my $location=&Apache::lonnet::filelocation('',$bodytext);
-       my $styletext=&Apache::lonnet::getfile($location);
-       if ($styletext ne '-1') {
-          %style_for_target = (%style_for_target,
-                          &Apache::style::styleparser($target,$styletext));
-       }
-    }
+	 foreach my $file (split(',',$bodytext)) {
+	     my $location=&Apache::lonnet::filelocation('',$file);
+	     my $styletext=&Apache::lonnet::getfile($location);
+	     if ($styletext ne '-1') {
+		 %style_for_target = (%style_for_target,
+				      &Apache::style::styleparser($target,$styletext));
+	     }
+	 }
+     }
  } elsif ($ENV{'construct.style'} && ($ENV{'request.state'} eq 'construct')) {
      my $location=&Apache::lonnet::filelocation('',$ENV{'construct.style'});
      my $styletext=&Apache::lonnet::getfile($location);
@@ -388,8 +399,10 @@ sub latex_special_symbols {
     } else {
 	$string=~s/\\/\\ensuremath{\\backslash}/g;
 	$string=~s/([^\\]|^)\%/$1\\\%/g;
-	$string=~s/([^\\]|^)(\$|_)/$1\\$2/g;
+	$string=~s/([^\\]|^)\$/$1\\\$/g;
+	$string=~s/([^\\])\_/$1\\_/g;
 	$string=~s/\$\$/\$\\\$/g;
+	$string=~s/\_\_/\_\\\_/g;
 	$string=~s/\#\#/\#\\\#/g;
         $string=~s/([^\\]|^)(\~|\^)/$1\\$2\\strut /g;
 	$string=~s/(>|<)/\\ensuremath\{$1\}/g; #more or less
@@ -397,6 +410,7 @@ sub latex_special_symbols {
 	# any & or # leftover should be safe to just escape
         $string=~s/([^\\]|^)\&/$1\\\&/g;
         $string=~s/([^\\]|^)\#/$1\\\#/g;
+        $string=~s/\|/\$\\mid\$/g;
 #single { or } How to escape?
     }
     return $string;
@@ -604,6 +618,7 @@ sub setup_globals {
   my ($request,$target)=@_;
   $Apache::lonxml::request=$request;
   $Apache::lonxml::registered = 0;
+  @Apache::lonxml::htmlareafields=();
   $errorcount=0;
   $warningcount=0;
   $Apache::lonxml::default_homework_loaded=0;
@@ -662,7 +677,9 @@ sub init_safespace {
   $safehole->wrap(\&Apache::scripttag::xmlparse,$safeeval,'&xmlparse');
   $safehole->wrap(\&Apache::outputtags::multipart,$safeeval,'&multipart');
   $safehole->wrap(\&Apache::lonnet::EXT,$safeeval,'&EXT');
-  
+  $safehole->wrap(\&Apache::chemresponse::chem_standard_order,$safeeval,
+		  '&chem_standard_order');
+
   $safehole->wrap(\&Math::Cephes::asin,$safeeval,'&asin');
   $safehole->wrap(\&Math::Cephes::acos,$safeeval,'&acos');
   $safehole->wrap(\&Math::Cephes::atan,$safeeval,'&atan');
@@ -736,9 +753,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::caparesponse::get_sigrange,$safeeval,'&LONCAPA_INTERNAL_get_sigrange');
 
 #need to inspect this class of ops
 # $safeeval->deny(":base_orig");
+  $safeeval->permit("require");
   $safeinit .= ';$external::target="'.$target.'";';
   my $rndseed;
   my ($symb,$courseid,$domain,$name) = &Apache::lonxml::whichuser();
@@ -747,27 +766,6 @@ sub init_safespace {
   &Apache::lonxml::debug("Setting rndseed to $rndseed");
   &Apache::run::run($safeinit,$safeeval);
 
-  my $subroutine=<<'EVALUATESUB';
-sub __LC_INTERNAL_EVALUATE__ {
-    my ($__LC__a,$__LC__b,$__LC__c)=@_;
-    my $__LC__prefix;
-    while(1){
-	{ 
-	    use strict;
-	    no strict "vars";
-	    if (eval(defined(eval($__LC__a.$__LC__b)))) {
-		return $__LC__prefix.eval($__LC__a.$__LC__b.$__LC__c);
-	    }
-	}
-	$__LC__prefix.=substr($__LC__a,0,1,"");
-	if ($__LC__a!~/^(\$|&|\#)/) { last; }
-    }
-    return $__LC__prefix.$__LC__a.$__LC__b.$__LC__c;
-}
-EVALUATESUB
-    $safeeval->permit("require");
-    $safeeval->reval($subroutine);
-    $safeeval->deny("require");
 }
 
 sub default_homework_load {
@@ -782,18 +780,26 @@ sub default_homework_load {
     }
 }
 
+my $metamode_was;
 sub startredirection {
-  $Apache::lonxml::redirection++;
-  push (@Apache::lonxml::outputstack, '');
+    if (!$Apache::lonxml::redirection) {
+	$metamode_was=$Apache::lonxml::metamode;
+    }
+    $Apache::lonxml::metamode=0;
+    $Apache::lonxml::redirection++;
+    push (@Apache::lonxml::outputstack, '');
 }
 
 sub endredirection {
-  if (!$Apache::lonxml::redirection) {
-    &Apache::lonxml::error("Endredirection was called, before a startredirection, perhaps you have unbalanced tags. Some debuging information:".join ":",caller);
-    return '';
-  }
-  $Apache::lonxml::redirection--;
-  pop @Apache::lonxml::outputstack;
+    if (!$Apache::lonxml::redirection) {
+	&Apache::lonxml::error("Endredirection was called, before a startredirection, perhaps you have unbalanced tags. Some debuging information:".join ":",caller);
+	return '';
+    }
+    $Apache::lonxml::redirection--;
+    if (!$Apache::lonxml::redirection) {
+	$Apache::lonxml::metamode=$metamode_was;
+    }
+    pop @Apache::lonxml::outputstack;
 }
 
 sub end_tag {
@@ -809,6 +815,8 @@ sub initdepth {
   $Apache::lonxml::olddepth=-1;
 }
 
+my @timers;
+my $lasttime;
 sub increasedepth {
   my ($token) = @_;
   $Apache::lonxml::depth++;
@@ -816,8 +824,12 @@ sub increasedepth {
   if ($Apache::lonxml::depthcounter[$Apache::lonxml::depth]==1) {
     $Apache::lonxml::olddepth=$Apache::lonxml::depth;
   }
+  push(@timers,[&gettimeofday()]);
+  my $time=&tv_interval($lasttime);
+  $lasttime=[&gettimeofday()];
+  my $spacing='  'x($Apache::lonxml::depth-1);
   my $curdepth=join('_',@Apache::lonxml::depthcounter);
-  &Apache::lonxml::debug("s $Apache::lonxml::depth : $Apache::lonxml::olddepth : $curdepth : $token->[1]\n");
+  &Apache::lonxml::debug("s$spacing$Apache::lonxml::depth : $Apache::lonxml::olddepth : $curdepth : $token->[1] : $time : \n");
 #print "<br />s $Apache::lonxml::depth : $Apache::lonxml::olddepth : $curdepth : $token->[1]\n";
 }
 
@@ -832,37 +844,41 @@ sub decreasedepth {
     &Apache::lonxml::warning(&mt("Missing tags, unable to properly run file."));
     $Apache::lonxml::depth='-1';
   }
+  my $timer=pop(@timers);
+  my $time=&tv_interval($lasttime);
+  $lasttime=[&gettimeofday()];
+  my $spacing='  'x$Apache::lonxml::depth;
   my $curdepth=join('_',@Apache::lonxml::depthcounter);
-  &Apache::lonxml::debug("e $Apache::lonxml::depth : $Apache::lonxml::olddepth : $token->[1] : $curdepth\n");
+  &Apache::lonxml::debug("e$spacing$Apache::lonxml::depth : $Apache::lonxml::olddepth : $curdepth : $token->[1] : $time : ".&tv_interval($timer)."\n");
 #print "<br />e $Apache::lonxml::depth : $Apache::lonxml::olddepth : $token->[1] : $curdepth\n";
 }
 
 sub get_all_text_unbalanced {
 #there is a copy of this in lonpublisher.pm
- my($tag,$pars)= @_;
- my $token;
- my $result='';
- $tag='<'.$tag.'>';
- while ($token = $$pars[-1]->get_token) {
-   if (($token->[0] eq 'T')||($token->[0] eq 'C')||($token->[0] eq 'D')) {
-     $result.=$token->[1];
-   } elsif ($token->[0] eq 'PI') {
-     $result.=$token->[2];
-   } elsif ($token->[0] eq 'S') {
-     $result.=$token->[4];
-   } elsif ($token->[0] eq 'E')  {
-     $result.=$token->[2];
-   }
-   if ($result =~ /(.*)\Q$tag\E(.*)/is) {
-     &Apache::lonxml::debug('Got a winner with leftovers ::'.$2);
-     &Apache::lonxml::debug('Result is :'.$1);
-     $result=$1;
-     my $redo=$tag.$2;
-     &Apache::lonxml::newparser($pars,\$redo);
-     last;
-   }
- }
- return $result
+    my($tag,$pars)= @_;
+    my $token;
+    my $result='';
+    $tag='<'.$tag.'>';
+    while ($token = $$pars[-1]->get_token) {
+	if (($token->[0] eq 'T')||($token->[0] eq 'C')||($token->[0] eq 'D')) {
+	    $result.=$token->[1];
+	} elsif ($token->[0] eq 'PI') {
+	    $result.=$token->[2];
+	} elsif ($token->[0] eq 'S') {
+	    $result.=$token->[4];
+	} elsif ($token->[0] eq 'E')  {
+	    $result.=$token->[2];
+	}
+	if ($result =~ /\Q$tag\E/is) {
+	    ($result,my $redo)=$result =~ /(.*)\Q$tag\E(.*)/is;
+	    #&Apache::lonxml::debug('Got a winner with leftovers ::'.$2);
+	    #&Apache::lonxml::debug('Result is :'.$1);
+	    $redo=$tag.$redo;
+	    &Apache::lonxml::newparser($pars,\$redo);
+	    last;
+	}
+    }
+    return $result
 }
 
 sub increment_counter {
@@ -1094,21 +1110,20 @@ sub storefile {
 }
 
 sub createnewhtml {
-  my $filecontents=(<<SIMPLECONTENT);
+    my $title=&mt('Title of document goes here');
+    my $body=&mt('Body of document goes here');
+    my $filecontents=(<<SIMPLECONTENT);
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml/11/DTD/xhtml11.dtd">
 <html>
 <head>
-<title>
-                           Title of Document Goes Here
-</title>
+<title>$title</title>
 </head>
 <body bgcolor="#FFFFFF">
-
-                           Body of Document Goes Here
-
+$body
 </body>
 </html>
 SIMPLECONTENT
-  return $filecontents;
+    return $filecontents;
 }
 
 sub createnewsty {
@@ -1129,8 +1144,25 @@ sub inserteditinfo {
       $filecontents = &HTML::Entities::encode($filecontents,'<>&"');
 #      my $editheader='<a href="#editsection">Edit below</a><hr />';
       my $xml_help = '';
+      my $initialize='';
       if ($filetype eq 'html') {
-	  $xml_help=Apache::loncommon::helpLatexCheatsheet();
+	  my $addbuttons=&Apache::lonhtmlcommon::htmlareaaddbuttons();
+	  $initialize=&Apache::lonhtmlcommon::htmlareaheaders().
+	      &Apache::lonhtmlcommon::spellheader().(<<FULLPAGE);
+<script type="text/javascript">
+$addbuttons
+
+    HTMLArea.loadPlugin("FullPage");
+
+    function initDocument() {
+	var editor=new HTMLArea("filecont",config);
+	editor.registerPlugin(FullPage);
+	editor.generate();
+    }
+</script>
+FULLPAGE
+          $result=~s/\<body([^\>]*)\>/\<body onload="initDocument()" $1\>/i;
+	  $xml_help=&Apache::loncommon::helpLatexCheatsheet();
       }
       my $cleanbut = '';
       if ($filetype eq 'html') {
@@ -1146,18 +1178,22 @@ $cleanbut
 <input type="submit" name="savethisfile" accesskey="s"  value="$lt{'st'}" />
 <input type="submit" name="viewmode" accesskey="v" value="$lt{'vi'}" />
 BUTTONS
+      $buttons.=&Apache::lonhtmlcommon::spelllink('xmledit','filecont');
+      $buttons.=&Apache::lonhtmlcommon::htmlareaselectactive('filecont');
       my $editfooter=(<<ENDFOOTER);
+$initialize
 <hr />
 <a name="editsection" />
-<form method="post">
+<form method="post" name="xmledit">
 $xml_help
 <input type="hidden" name="editmode" value="$lt{'ed'}" />
 $buttons<br />
-<textarea cols="80" rows="40" name="filecont">$filecontents</textarea>
+<textarea cols="80" rows="44" name="filecont" id="filecont">$filecontents</textarea>
 <br />$buttons
 <br />
 </form>
 $titledisplay
+</body>
 ENDFOOTER
 #      $result=~s/(\<body[^\>]*\>)/$1$editheader/is;
       $result=~s/(\<\/body\>)/$editfooter/is;
@@ -1312,35 +1348,46 @@ sub debug {
 	my $request=$Apache::lonxml::request;
 	if (!$request) { $request=Apache->request; }
 	$request->print('<font size="-2"><pre>DEBUG:'.&HTML::Entities::encode($_[0],'<>&"')."</pre></font>\n");
+#	&Apache::lonnet::logthis($_[0]);
     }
 }
 
 sub error {
-  $errorcount++;
-  my $request=$Apache::lonxml::request;
-  if (!$request) { $request=Apache->request; }
-  if (($Apache::lonxml::debug eq 1) || ($ENV{'request.state'} eq 'construct') ) {
-    # If printing in construction space, put the error inside <pre></pre>
-      push(@Apache::lonxml::error_messages,
-	   $Apache::lonxml::warnings_error_header.
-	   "<b>ERROR:</b>".join("<br />\n",@_)."<br />\n");
-      $Apache::lonxml::warnings_error_header='';
-  } else {
-      push(@Apache::lonxml::error_messages,
-	   "<b>An Error occured while processing this resource. The instructor has been notified.</b> <br />");
-    #notify author
-    &Apache::lonmsg::author_res_msg($ENV{'request.filename'},join('<br />',@_));
-    #notify course
-    if ( $ENV{'request.course.id'} ) {
-      my (undef,%users)=&Apache::lonfeedback::decide_receiver(undef,0,1,1,1);
-      my $declutter=&Apache::lonnet::declutter($ENV{'request.filename'});
-      foreach (keys %users) {
-	my ($user,$domain) = split(/:/, $_);
-	&Apache::lonmsg::user_normal_msg($user,$domain,
-        "Error [$declutter]",join('<br />',@_));
-      }
+    $errorcount++;
+    if (($Apache::lonxml::debug eq 1) || ($ENV{'request.state'} eq 'construct') ) {
+	# If printing in construction space, put the error inside <pre></pre>
+	push(@Apache::lonxml::error_messages,
+	     $Apache::lonxml::warnings_error_header.
+	     "<b>ERROR:</b>".join("<br />\n",@_)."<br />\n");
+	$Apache::lonxml::warnings_error_header='';
+    } else {
+	my $errormsg;
+	my ($symb)=&Apache::lonnet::symbread();
+	if ( !$symb ) {
+	    #public or browsers
+	    $errormsg=&mt("An error occured while processing this resource. The author has been notified.");
+	} 
+	#notify author
+	&Apache::lonmsg::author_res_msg($ENV{'request.filename'},join('<br />',@_));
+	#notify course
+	if ( $symb && $ENV{'request.course.id'} ) {
+	    my (undef,%users)=&Apache::lonfeedback::decide_receiver(undef,0,1,1,1);
+	    my $declutter=&Apache::lonnet::declutter($ENV{'request.filename'});
+	    my @userlist;
+	    foreach (keys %users) {
+		my ($user,$domain) = split(/:/, $_);
+		push(@userlist,"$user\@$domain");
+		&Apache::lonmsg::user_normal_msg($user,$domain,
+						 "Error [$declutter]",join('<br />',@_));
+	    }
+	    if ($ENV{'request.role.adv'}) {
+		$errormsg=&mt("An error occured while processing this resource. The course personnel ([_1]) and the author have been notified.",join(', ',@userlist));
+	    } else {
+		$errormsg=&mt("An error occured while processing this resource. The instructor has been notified.");
+	    }
+	}
+	push(@Apache::lonxml::error_messages,"<b>$errormsg</b> <br />");
     }
-  }
 }
 
 sub warning {