--- loncom/xml/lonxml.pm	2003/05/02 19:57:01	1.250
+++ loncom/xml/lonxml.pm	2003/08/11 20:05:53	1.270
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # XML Parser Module 
 #
-# $Id: lonxml.pm,v 1.250 2003/05/02 19:57:01 albertel Exp $
+# $Id: lonxml.pm,v 1.270 2003/08/11 20:05:53 albertel Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -70,6 +70,7 @@ use Math::Cephes();
 use Math::Random();
 use Opcode();
 
+
 sub register {
   my ($space,@taglist) = @_;
   foreach my $temptag (@taglist) {
@@ -95,6 +96,8 @@ use Apache::run();
 use Apache::londefdef();
 use Apache::scripttag();
 use Apache::edit();
+use Apache::inputtags();
+use Apache::outputtags();
 use Apache::lonnet();
 use Apache::File();
 use Apache::loncommon();
@@ -151,6 +154,10 @@ $Apache::lonxml::counter_changed=0;
 #internal check on whether to look at style defs
 $Apache::lonxml::usestyle=1;
 
+#locations used to store the parameter string for style substitutions
+$Apache::lonxml::style_values='';
+$Apache::lonxml::style_end_values='';
+
 sub xmlbegin {
   my $output='';
   if ($ENV{'browser.mathml'}) {
@@ -382,7 +389,7 @@ sub fontsettings() {
     if (($ENV{'browser.os'} eq 'mac') && (!$ENV{'browser.mathml'})) { 
 	$headerstring.=
 	    '<meta Content-Type="text/html; charset=x-mac-roman">';
-    } elsif (!$ENV{'browser.mathml'}) {
+    } elsif (!$ENV{'browser.mathml'} && $ENV{'browser.unicode'}) {
 	$headerstring.=
 	    '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
     }
@@ -421,8 +428,7 @@ sub xmlparse {
        }
     }
  }
-
- #&printalltags();
+#&printalltags();
  my @pars = ();
  my $pwd=$ENV{'request.filename'};
  $pwd =~ s:/[^/]*$::;
@@ -441,6 +447,7 @@ sub xmlparse {
 
  my $finaloutput = &inner_xmlparse($target,\@stack,\@parstack,\@pars,
 				   $safeeval,\%style_for_target);
+
  if ($ENV{'request.uri'}) {
     &writeallows($ENV{'request.uri'});
  }
@@ -485,6 +492,7 @@ sub latex_special_symbols {
 	$current_token=~s/(>|<)/\$$1\$/g; #more or less
 	if ($current_token=~m/\d%/) {$current_token =~ s/(\d)%/$1\\%/g;} #percent after digit
 	if ($current_token=~m/\s%/) {$current_token =~ s/(\s)%/$1\\%/g;} #persent after space
+	if ($current_token eq '%.') {$current_token = '\%.';} #persent at the end of statement
     }
     return $current_token;
 }
@@ -494,9 +502,10 @@ sub inner_xmlparse {
   my $finaloutput = '';
   my $result;
   my $token;
+  my $dontpop=0;
   while ( $#$pars > -1 ) {
     while ($token = $$pars['-1']->get_token) {
-      if (($token->[0] eq 'T') || ($token->[0] eq 'C') || ($token->[0] eq 'D') ) {
+      if (($token->[0] eq 'T') || ($token->[0] eq 'C') ) {
 	if ($metamode<1) {
 	    my $text=$token->[1];
 	    if ($token->[0] eq 'C' && $target eq 'tex') {
@@ -505,8 +514,13 @@ sub inner_xmlparse {
 	    }
 	    $result.=$text;
 	}
+      } elsif (($token->[0] eq 'D')) {
+	if ($metamode<1 && $target eq 'web') {
+	    my $text=$token->[1];
+	    $result.=$text;
+	}
       } elsif ($token->[0] eq 'PI') {
-	if ($metamode<1) {
+	if ($metamode<1 && $target eq 'web') {
 	  $result=$token->[2];
 	}
       } elsif ($token->[0] eq 'S') {
@@ -521,42 +535,50 @@ sub inner_xmlparse {
 	    my $string=$$style_for_target{$token->[1]}.
 	      '<LONCAPA_INTERNAL_TURN_STYLE_ON />';
 	    &Apache::lonxml::newparser($pars,\$string);
+	    $Apache::lonxml::style_values=$$parstack[-1];
+	    $Apache::lonxml::style_end_values=$$parstack[-1];
 	} else {
 	  $result = &callsub("start_$token->[1]", $target, $token, $stack,
 			     $parstack, $pars, $safeeval, $style_for_target);
 	}
       } elsif ($token->[0] eq 'E') {
-	#clear out any tags that didn't end
-	while ($token->[1] ne $$stack['-1'] && ($#$stack > -1)) {
-	  my $lasttag=$$stack[-1];
-	  if ($token->[1] =~ /^$lasttag$/i) {
-	    &Apache::lonxml::warning('Using tag &lt;/'.$token->[1].'&gt; on line '.$token->[3].' as end tag to &lt;'.$$stack[-1].'&gt;');
-	    last;
-	  } else {
-	    &Apache::lonxml::warning('Found tag &lt;/'.$token->[1].'&gt; on line '.$token->[3].' when looking for &lt;/'.$$stack[-1].'&gt; in file');
-	    &end_tag($stack,$parstack,$token);
-	  }
-	}
-
 	if ($Apache::lonxml::usestyle &&
 	    exists($$style_for_target{'/'."$token->[1]"})) {
 	    $Apache::lonxml::usestyle=0;
 	    my $string=$$style_for_target{'/'.$token->[1]}.
-	      '<LONCAPA_INTERNAL_TURN_STYLE_ON />';
+	      '<LONCAPA_INTERNAL_TURN_STYLE_ON end="'.$token->[1].'" />';
 	    &Apache::lonxml::newparser($pars,\$string);
+	    $Apache::lonxml::style_values=$Apache::lonxml::style_end_values;
+	    $Apache::lonxml::style_end_values='';
+	    $dontpop=1;
 	} else {
-	  $result = &callsub("end_$token->[1]", $target, $token, $stack,
-			     $parstack, $pars,$safeeval, $style_for_target);
+	    #clear out any tags that didn't end
+	    while ($token->[1] ne $$stack['-1'] && ($#$stack > -1)) {
+		my $lasttag=$$stack[-1];
+		if ($token->[1] =~ /^$lasttag$/i) {
+		    &Apache::lonxml::warning('Using tag &lt;/'.$token->[1].'&gt; on line '.$token->[3].' as end tag to &lt;'.$$stack[-1].'&gt;');
+		    last;
+		} else {
+		    &Apache::lonxml::warning('Found tag &lt;/'.$token->[1].'&gt; on line '.$token->[3].' when looking for &lt;/'.$$stack[-1].'&gt; in file');
+		    &end_tag($stack,$parstack,$token);
+		}
+	    }
+	    $result = &callsub("end_$token->[1]", $target, $token, $stack,
+			       $parstack, $pars,$safeeval, $style_for_target);
 	}
       } else {
 	&Apache::lonxml::error("Unknown token event :$token->[0]:$token->[1]:");
       }
       #evaluate variable refs in result
       if ($result ne "") {
+	  my $extras;
+	  if (!$Apache::lonxml::usestyle) {
+	      $extras=$Apache::lonxml::style_values;
+	  }
 	if ( $#$parstack > -1 ) {
-	  $result=&Apache::run::evaluate($result,$safeeval,$$parstack[-1]);
+	  $result=&Apache::run::evaluate($result,$safeeval,$extras.$$parstack[-1]);
 	} else {
-	  $result= &Apache::run::evaluate($result,$safeeval,'');
+	  $result= &Apache::run::evaluate($result,$safeeval,$extras);
 	}
       }
       if (($token->[0] eq 'T') || ($token->[0] eq 'C') || ($token->[0] eq 'D') ) {
@@ -577,9 +599,10 @@ sub inner_xmlparse {
       }
       $result = '';
 
-      if ($token->[0] eq 'E') { 
+      if ($token->[0] eq 'E' && !$dontpop) {
 	&end_tag($stack,$parstack,$token);
       }
+      $dontpop=0;
     }	
     if ($#$pars > -1) {
 	pop @$pars;
@@ -722,6 +745,7 @@ sub init_safespace {
   $safeeval->permit("sort");
   $safeeval->deny(":base_io");
   $safehole->wrap(\&Apache::scripttag::xmlparse,$safeeval,'&xmlparse');
+  $safehole->wrap(\&Apache::outputtags::multipart,$safeeval,'&multipart');
   $safehole->wrap(\&Apache::lonnet::EXT,$safeeval,'&EXT');
   
   $safehole->wrap(\&Math::Cephes::asin,$safeeval,'&asin');
@@ -928,83 +952,105 @@ sub store_counter {
 }
 
 sub get_all_text {
- my($tag,$pars)= @_;
- &Apache::lonxml::debug("Got a ".ref($pars));
- my $gotfullstack=1;
- if (ref($pars) ne 'ARRAY') {
-     $gotfullstack=0;
-     $pars=[$pars];
- }
- my $depth=0;
- my $token;
- my $result='';
- if ( $tag =~ m:^/: ) { 
-   my $tag=substr($tag,1); 
-   #&Apache::lonxml::debug("have:$tag:");
-   my $top_empty=0;
-   while (($depth >=0) && ($#$pars > -1) && (!$top_empty)) {
-     while (($depth >=0) && ($token = $$pars[-1]->get_token)) {
-       #&Apache::lonxml::debug("e token:$token->[0]:$depth:$token->[1]:".$#$pars.":".$#Apache::lonxml::pwd);
-       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') {
-	 if ($token->[1] =~ /^$tag$/i) { $depth++; }
-	 $result.=$token->[4];
-       } elsif ($token->[0] eq 'E')  {
-	 if ( $token->[1] =~ /^$tag$/i) { $depth--; }
-	 #skip sending back the last end tag
-	 if ($depth > -1) { $result.=$token->[2]; } else {
-	   $$pars[-1]->unget_token($token);
-	 }
-       }
-     }
-     if (($depth >=0) && ($#$pars == 0) ) { $top_empty=1; }
-     if (($depth >=0) && ($#$pars > 0) ) {
-       pop(@$pars);
-       pop(@Apache::lonxml::pwd);
-     }
-   }
-   if ($top_empty && $depth >= 0) {
-       #never found the end tag ran out of text, throw error send back blank
-       &error('Never found end tag for &lt;'.$tag.'&gt;');
-       if ($gotfullstack) {
-	   my $newstring='</'.$tag.'>'.$result;
-	   &Apache::lonxml::newparser($pars,\$newstring);
-       }
-       $result='';
-   }
- } else {
-     while ($#$pars > -1) {
-	 while ($token = $$pars[-1]->get_token) {
-	     #&Apache::lonxml::debug("s token:$token->[0]:$depth:$token->[1]");
-	     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') {
-		 if ( $token->[1] =~ /^$tag$/i) {
-		     $$pars[-1]->unget_token($token); last;
-		 } else {
-		     $result.=$token->[4];
-		 }
-	     } elsif ($token->[0] eq 'E')  {
-		 $result.=$token->[2];
-	     }
-	 }
-	 if (($#$pars > 0) ) {
-	     pop(@$pars);
-	     pop(@Apache::lonxml::pwd);
-	 } else { last; }
-     }
- }
- if ($result =~ m|<LONCAPA_INTERNAL_TURN_STYLE_ON />|) {
-     $Apache::lonxml::usestyle=1;
- }
- #&Apache::lonxml::debug("Exit:$result:");
- return $result
+    my($tag,$pars,$style)= @_;
+    &Apache::lonxml::debug("Got a ".ref($pars));
+    my $gotfullstack=1;
+    if (ref($pars) ne 'ARRAY') {
+	$gotfullstack=0;
+	$pars=[$pars];
+    }
+    &Apache::lonxml::debug("Got a ".ref($style));
+    if (ref($style) ne 'HASH') {
+	$style={};
+    } else {
+	&Apache::lonhomework::showhash(%$style);
+    }
+    my $depth=0;
+    my $token;
+    my $result='';
+    if ( $tag =~ m:^/: ) { 
+	my $tag=substr($tag,1); 
+	#&Apache::lonxml::debug("have:$tag:");
+	my $top_empty=0;
+	while (($depth >=0) && ($#$pars > -1) && (!$top_empty)) {
+	    while (($depth >=0) && ($token = $$pars[-1]->get_token)) {
+		#&Apache::lonxml::debug("e token:$token->[0]:$depth:$token->[1]:".$#$pars.":".$#Apache::lonxml::pwd);
+		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') {
+		    if ($token->[1] =~ /^$tag$/i) { $depth++; }
+		    if ($token->[1] =~ /^LONCAPA_INTERNAL_TURN_STYLE_ON$/i) { $Apache::lonxml::usestyle=1; }
+		    if ($token->[1] =~ /^LONCAPA_INTERNAL_TURN_STYLE_OFF$/i) { $Apache::lonxml::usestyle=0; }
+		    $result.=$token->[4];
+		} elsif ($token->[0] eq 'E')  {
+		    if ( $token->[1] =~ /^$tag$/i) { $depth--; }
+		    #skip sending back the last end tag
+		    if ($depth == 0 && exists($$style{'/'.$token->[1]})) {
+			my $string=
+			    '<LONCAPA_INTERNAL_TURN_STYLE_OFF end="yes" />'.
+				$$style{'/'.$token->[1]}.
+				    $token->[2].
+					'<LONCAPA_INTERNAL_TURN_STYLE_ON />';
+			&Apache::lonxml::newparser($pars,\$string);
+			#&Apache::lonxml::debug("reParsing $string");
+			next;
+		    }
+		    if ($depth > -1) {
+			$result.=$token->[2];
+		    } else {
+			$$pars[-1]->unget_token($token);
+		    }
+		}
+	    }
+	    if (($depth >=0) && ($#$pars == 0) ) { $top_empty=1; }
+	    if (($depth >=0) && ($#$pars > 0) ) {
+		pop(@$pars);
+		pop(@Apache::lonxml::pwd);
+	    }
+	}
+	if ($top_empty && $depth >= 0) {
+	    #never found the end tag ran out of text, throw error send back blank
+	    &error('Never found end tag for &lt;'.$tag.
+		   '&gt; current string <pre>'.
+		   &HTML::Entities::encode($result).
+		   '</pre>');
+	    if ($gotfullstack) {
+		my $newstring='</'.$tag.'>'.$result;
+		&Apache::lonxml::newparser($pars,\$newstring);
+	    }
+	    $result='';
+	}
+    } else {
+	while ($#$pars > -1) {
+	    while ($token = $$pars[-1]->get_token) {
+		#&Apache::lonxml::debug("s token:$token->[0]:$depth:$token->[1]");
+		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') {
+		    if ( $token->[1] =~ /^$tag$/i) {
+			$$pars[-1]->unget_token($token); last;
+		    } else {
+			$result.=$token->[4];
+		    }
+		    if ($token->[1] =~ /^LONCAPA_INTERNAL_TURN_STYLE_ON$/i) { $Apache::lonxml::usestyle=1; }
+		    if ($token->[1] =~ /^LONCAPA_INTERNAL_TURN_STYLE_OFF$/i) { $Apache::lonxml::usestyle=0; }
+		} elsif ($token->[0] eq 'E')  {
+		    $result.=$token->[2];
+		}
+	    }
+	    if (($#$pars > 0) ) {
+		pop(@$pars);
+		pop(@Apache::lonxml::pwd);
+	    } else { last; }
+	}
+    }
+    #&Apache::lonxml::debug("Exit:$result:");
+    return $result
 }
 
 sub newparser {
@@ -1016,8 +1062,6 @@ sub newparser {
   } else {
     push (@Apache::lonxml::pwd, $dir);
   } 
-#  &Apache::lonxml::debug("pwd:$#Apache::lonxml::pwd");
-#  &Apache::lonxml::debug("pwd:$Apache::lonxml::pwd[$#Apache::lonxml::pwd]");
 }
 
 sub parstring {
@@ -1028,7 +1072,7 @@ sub parstring {
       my $val=$token->[2]->{$_};
       $val =~ s/([\%\@\\\"\'])/\\$1/g;
       #if ($val =~ m/^[\%\@]/) { $val="\\".$val; }
-      $temp .= "my \$$_=\"$val\";"
+      $temp .= "my \$$_=\"$val\";";
     }
   }
   return $temp;
@@ -1121,13 +1165,8 @@ sub inserteditinfo {
       my ($result,$filecontents)=@_;
       $filecontents = &HTML::Entities::encode($filecontents);
 #      my $editheader='<a href="#editsection">Edit below</a><hr />';
-      my $xml_help = '<table><tr><td>'.
-	  &Apache::loncommon::help_open_topic("Greek_Symbols",'Greek Symbols',
-					      undef,undef,600)
-	      .'</td><td>'.
-          &Apache::loncommon::help_open_topic("Other_Symbols",'Other Symbols',
-					      undef,undef,600)
-	      .'</td></tr></table>';
+      my $xml_help = Apache::loncommon::helpLatexCheatsheet();
+      my $titledisplay=&display_title();
       my $buttons=(<<BUTTONS);
 <input type="submit" name="attemptclean" 
        value="Save and then attempt to clean HTML" />
@@ -1145,6 +1184,7 @@ $buttons<br />
 <br />$buttons
 <br />
 </form>
+$titledisplay
 ENDFOOTER
 #      $result=~s/(\<body[^\>]*\>)/$1$editheader/is;
       $result=~s/(\<\/body\>)/$editfooter/is;
@@ -1179,37 +1219,37 @@ sub get_target {
 }
 
 sub handler {
-  my $request=shift;
-
-  my $target=&get_target();
-
-  $Apache::lonxml::debug=0;
-
-  if ($ENV{'browser.mathml'}) {
-    $request->content_type('text/xml');
-  } else {
-    $request->content_type('text/html');
-  }
-  &Apache::loncommon::no_cache($request);
-  $request->send_http_header;
-
-  return OK if $request->header_only;
+    my $request=shift;
+    
+    my $target=&get_target();
+    
+    $Apache::lonxml::debug=$ENV{'user.debug'};
+    
+    if ($ENV{'browser.mathml'}) {
+	$request->content_type('text/xml');
+    } else {
+	$request->content_type('text/html');
+    }
+    &Apache::loncommon::no_cache($request);
+    $request->send_http_header;
+    
+    return OK if $request->header_only;
 
 
-  my $file=&Apache::lonnet::filelocation("",$request->uri);
+    my $file=&Apache::lonnet::filelocation("",$request->uri);
 #
 # Edit action? Save file.
 #
-  unless ($ENV{'request.state'} eq 'published') {
-      if (($ENV{'form.savethisfile'}) || ($ENV{'form.attemptclean'})) {
-	  &storefile($file,$ENV{'form.filecont'});
-      }
-  }
-  my %mystyle;
-  my $result = '';
-  my $filecontents=&Apache::lonnet::getfile($file);
-  if ($filecontents eq -1) {
-    $result=(<<ENDNOTFOUND);
+    unless ($ENV{'request.state'} eq 'published') {
+	if (($ENV{'form.savethisfile'}) || ($ENV{'form.attemptclean'})) {
+	    &storefile($file,$ENV{'form.filecont'});
+	}
+    }
+    my %mystyle;
+    my $result = '';
+    my $filecontents=&Apache::lonnet::getfile($file);
+    if ($filecontents eq -1) {
+	$result=(<<ENDNOTFOUND);
 <html>
 <head>
 <title>File not found</title>
@@ -1220,40 +1260,58 @@ sub handler {
 </html>
 ENDNOTFOUND
     $filecontents='';
-    if ($ENV{'request.state'} ne 'published') {
-      $filecontents=&createnewhtml();
-      $ENV{'form.editmode'}='Edit'; #force edit mode
-    }
-  } else {
-    unless ($ENV{'request.state'} eq 'published') {
-      if ($ENV{'form.attemptclean'}) {
-	$filecontents=&htmlclean($filecontents,1);
-      }
-    }
-    if (!$ENV{'form.editmode'} || $ENV{'form.viewmode'}) {
-      $result = &Apache::lonxml::xmlparse($request,$target,$filecontents,
-					  '',%mystyle);
+	if ($ENV{'request.state'} ne 'published') {
+	    $filecontents=&createnewhtml();
+	    $ENV{'form.editmode'}='Edit'; #force edit mode
+	}
+    } else {
+	unless ($ENV{'request.state'} eq 'published') {
+	    if ($ENV{'form.attemptclean'}) {
+		$filecontents=&htmlclean($filecontents,1);
+	    }
+#
+# we are in construction space, see if edit mode forced
+            &Apache::loncommon::get_unprocessed_cgi
+                          ($ENV{'QUERY_STRING'},['editmode']);
+	}
+	if (!$ENV{'form.editmode'} || $ENV{'form.viewmode'}) {
+	    $result = &Apache::lonxml::xmlparse($request,$target,$filecontents,
+						'',%mystyle);
+	}
     }
-  }
-
+    
 #
 # Edit action? Insert editing commands
 #
-  unless ($ENV{'request.state'} eq 'published') {
-    if ($ENV{'form.editmode'} && (!($ENV{'form.viewmode'}))) {
-	my $displayfile=$request->uri;
-        $displayfile=~s/^\/[^\/]*//;
-      $result='<html><body bgcolor="#FFFFFF"><h3>'.$displayfile.
-              '</h3></body></html>';
-      $result=&inserteditinfo($result,$filecontents);
+    unless ($ENV{'request.state'} eq 'published') {
+	if ($ENV{'form.editmode'} && (!($ENV{'form.viewmode'}))) {
+	    my $displayfile=$request->uri;
+	    $displayfile=~s/^\/[^\/]*//;
+	    $result='<html><body bgcolor="#FFFFFF"><h3>'.$displayfile.
+		'</h3></body></html>';
+	    $result=&inserteditinfo($result,$filecontents);
+	}
     }
-  }
-
-  writeallows($request->uri);
-
-  $request->print($result);
-
-  return OK;
+    
+    writeallows($request->uri);
+    
+
+    $request->print($result);
+    
+    return OK;
+}
+
+sub display_title {
+    my $result;
+    if ($ENV{'request.state'} eq 'construct') {
+	my $title=&Apache::lonnet::gettitle();
+	if (!defined($title) || $title eq '') {
+	    $title = $ENV{'request.filename'};
+	    $title = substr($title, rindex($title, '/') + 1);
+	}
+	$result = "<script type='text/javascript'>top.document.title = '$title - LON-CAPA Construction Space';</script>";
+    }
+    return $result;
 }
 
 sub debug {
@@ -1291,8 +1349,11 @@ sub error {
 
 sub warning {
   $warningcount++;
-  if ($ENV{'request.state'} eq 'construct') {
-    print "<b>W</b>ARNING<b>:</b>".join('<br />',@_)."<br />\n";
+  
+  if ($ENV{'form.grade_target'} ne 'tex') {
+      if ($ENV{'request.state'} eq 'construct' || $Apache::lonxml::debug) {
+        print "<b>W</b>ARNING<b>:</b>".join('<br />',@_)."<br />\n";
+      }
   }
 }
 
@@ -1354,7 +1415,7 @@ sub register_insert {
     my $line = $data[$i];
     if ( $line =~ /^\#/ || $line =~ /^\s*\n/) { next; }
     if ( $line =~ /TABLE/ ) { last; }
-    my ($tag,$descrip,$color,$function,$show) = split(/,/, $line);
+    my ($tag,$descrip,$color,$function,$show,$helpfile,$helpdesc) = split(/,/, $line);
     if ($tag) {
       $insertlist{"$tagnum.tag"} = $tag;
       $insertlist{"$tagnum.description"} = $descrip;
@@ -1362,6 +1423,8 @@ sub register_insert {
       $insertlist{"$tagnum.function"} = $function;
       if (!defined($show)) { $show='yes'; }
       $insertlist{"$tagnum.show"}= $show;
+      $insertlist{"$tagnum.helpfile"} = $helpfile;
+      $insertlist{"$tagnum.helpdesc"} = $helpdesc;
       $insertlist{"$tag.num"}=$tagnum;
       $tagnum++;
     }
@@ -1396,15 +1459,30 @@ sub description {
   return $insertlist{$tagnum.'.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'});
+}
+
 # ----------------------------------------------------------------- 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=$ENV{'form.grade_courseid'};
-    my $allowed=&Apache::lonnet::allowed('mgr',$tmp_courseid);
+    my $allowed=&Apache::lonnet::allowed('vgr',$tmp_courseid);
     if ($allowed) {
       $symb=$ENV{'form.grade_symb'};
       $courseid=$ENV{'form.grade_courseid'};
@@ -1412,7 +1490,11 @@ sub whichuser {
       $name=$ENV{'form.grade_username'};
     }
   } else {
-      $symb=&Apache::lonnet::symbread();
+      if (!$passedsymb) {
+          $symb=&Apache::lonnet::symbread();
+      } else {
+          $symb=$passedsymb;
+      }
       $courseid=$ENV{'request.course.id'};
       $domain=$ENV{'user.domain'};
       $name=$ENV{'user.name'};