--- loncom/interface/lonhelper.pm	2005/01/10 12:15:23	1.92
+++ loncom/interface/lonhelper.pm	2005/04/11 18:13:39	1.102
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # .helper XML handler to implement the LON-CAPA helper
 #
-# $Id: lonhelper.pm,v 1.92 2005/01/10 12:15:23 foxr Exp $
+# $Id: lonhelper.pm,v 1.102 2005/04/11 18:13:39 albertel Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -25,10 +25,6 @@
 #
 # http://www.lon-capa.org/
 #
-# (Page Handler
-#
-# (.helper handler
-#
 
 =pod
 
@@ -186,6 +182,7 @@ use Apache::Constants qw(:common);
 use Apache::File;
 use Apache::lonxml;
 use Apache::lonlocal;
+use Apache::lonnet;
 
 # Register all the tags with the helper, so the helper can 
 # push and pop them
@@ -255,7 +252,7 @@ sub real_handler {
     my $r = shift;
     my $uri = shift;
     if (!defined($uri)) { $uri = $r->uri(); }
-    $ENV{'request.uri'} = $uri;
+    $env{'request.uri'} = $uri;
     my $filename = '/home/httpd/html' . $uri;
     my $fh = Apache::File->new($filename);
     my $file;
@@ -263,7 +260,7 @@ sub real_handler {
 
 
     # Send header, don't cache this page
-    if ($ENV{'browser.mathml'}) {
+    if ($env{'browser.mathml'}) {
 	&Apache::loncommon::content_type($r,'text/xml');
     } else {
 	&Apache::loncommon::content_type($r,'text/html');
@@ -278,7 +275,7 @@ sub real_handler {
 
     my $allowed = $helper->allowedCheck();
     if (!$allowed) {
-        $ENV{'user.error.msg'} = $ENV{'request.uri'}.':'.$helper->{REQUIRED_PRIV}.
+        $env{'user.error.msg'} = $env{'request.uri'}.':'.$helper->{REQUIRED_PRIV}.
             ":0:0:Permission denied to access this helper.";
         return HTTP_NOT_ACCEPTABLE;
     }
@@ -363,6 +360,7 @@ use HTML::Entities();
 use Apache::loncommon;
 use Apache::File;
 use Apache::lonlocal;
+use Apache::lonnet;
 
 sub new {
     my $proto = shift;
@@ -374,16 +372,16 @@ sub new {
     
     # If there is a state from the previous form, use that. If there is no
     # state, use the start state parameter.
-    if (defined $ENV{"form.CURRENT_STATE"})
+    if (defined $env{"form.CURRENT_STATE"})
     {
-	$self->{STATE} = $ENV{"form.CURRENT_STATE"};
+	$self->{STATE} = $env{"form.CURRENT_STATE"};
     }
     else
     {
 	$self->{STATE} = "START";
     }
 
-    $self->{TOKEN} = $ENV{'form.TOKEN'};
+    $self->{TOKEN} = $env{'form.TOKEN'};
     # If a token was passed, we load that in. Otherwise, we need to create a 
     # new storage file
     # Tried to use standard Tie'd hashes, but you can't seem to take a 
@@ -416,16 +414,16 @@ sub new {
             return undef;
         }
         # Must create the storage
-        $self->{TOKEN} = md5_hex($ENV{'user.name'} . $ENV{'user.domain'} .
+        $self->{TOKEN} = md5_hex($env{'user.name'} . $env{'user.domain'} .
                                  time() . rand());
         $self->{FILENAME} = $Apache::lonnet::tmpdir . md5_hex($self->{TOKEN});
     }
 
     # OK, we now have our persistent storage.
 
-    if (defined $ENV{"form.RETURN_PAGE"})
+    if (defined $env{"form.RETURN_PAGE"})
     {
-	$self->{RETURN_PAGE} = $ENV{"form.RETURN_PAGE"};
+	$self->{RETURN_PAGE} = $env{"form.RETURN_PAGE"};
     }
     else
     {
@@ -486,11 +484,11 @@ sub declareVar {
     }
 
     my $envname = 'form.' . $var . '.forminput';
-    if (defined($ENV{$envname})) {
-        if (ref($ENV{$envname})) {
-            $self->{VARS}->{$var} = join('|||', @{$ENV{$envname}});
+    if (defined($env{$envname})) {
+        if (ref($env{$envname})) {
+            $self->{VARS}->{$var} = join('|||', @{$env{$envname}});
         } else {
-            $self->{VARS}->{$var} = $ENV{$envname};
+            $self->{VARS}->{$var} = $env{$envname};
         }
     }
 }
@@ -502,7 +500,7 @@ sub allowedCheck {
         return 1;
     }
 
-    return Apache::lonnet::allowed($self->{REQUIRED_PRIV}, $ENV{'request.course.id'});
+    return Apache::lonnet::allowed($self->{REQUIRED_PRIV}, $env{'request.course.id'});
 }
 
 sub changeState {
@@ -524,7 +522,7 @@ sub process {
     # Phase 1: Post processing for state of previous screen (which is actually
     # the "current state" in terms of the helper variables), if it wasn't the 
     # beginning state.
-    if ($self->{STATE} ne "START" || $ENV{"form.SUBMIT"} eq &mt("Next ->")) {
+    if ($self->{STATE} ne "START" || $env{"form.SUBMIT"} eq &mt("Next ->")) {
 	my $prevState = $self->{STATES}{$self->{STATE}};
         $prevState->postprocess();
     }
@@ -575,6 +573,7 @@ sub display {
     }
 
     # Phase 4: Display.
+    my $html=&Apache::lonxml::xmlbegin();
     my $stateTitle=&mt($state->title());
     my $helperTitle = &mt($self->{TITLE});
     my $bodytag = &Apache::loncommon::bodytag($helperTitle,'','');
@@ -584,9 +583,8 @@ sub display {
     my $loncapaHelper = &mt("LON-CAPA Helper:");
 
     $result .= <<HEADER;
-<html>
+$html
     <head>
-        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
         <title>$loncapaHelper: $helperTitle</title>
     </head>
     $bodytag
@@ -1115,6 +1113,7 @@ no strict;
 @ISA = ("Apache::lonhelper::element");
 use strict;
 use Apache::lonlocal;
+use Apache::lonnet;
 
 BEGIN {
     &Apache::lonhelper::register('Apache::lonhelper::choices',
@@ -1165,7 +1164,7 @@ sub start_choice {
                                               $parser));
     my $nextstate = $token->[2]{'nextstate'};
     my $evalFlag = $token->[2]{'eval'};
-    push @{$paramHash->{CHOICES}}, [$human, $computer, $nextstate, 
+    push @{$paramHash->{CHOICES}}, [&mtn($human), $computer, $nextstate, 
                                     $evalFlag];
     return '';
 }
@@ -1281,7 +1280,7 @@ BUTTONS
             $choiceLabel = &$choiceLabel($helper, $self);
         }
         $result .= "/></td><td> ".qq{<label for="$id">}.
-            &mtn($choiceLabel). "</label></td></tr>\n";
+            $choiceLabel. "</label></td></tr>\n";
     }
     $result .= "</table>\n\n\n";
     $result .= $buttons;
@@ -1293,7 +1292,7 @@ BUTTONS
 # given, switch to it
 sub postprocess {
     my $self = shift;
-    my $chosenValue = $ENV{'form.' . $self->{'variable'} . '.forminput'};
+    my $chosenValue = $env{'form.' . $self->{'variable'} . '.forminput'};
 
     if (!defined($chosenValue) && !$self->{'allowempty'}) {
         $self->{ERROR_MSG} = 
@@ -1347,6 +1346,7 @@ no strict;
 @ISA = ("Apache::lonhelper::element");
 use strict;
 use Apache::lonlocal;
+use Apache::lonnet;
 
 BEGIN {
     &Apache::lonhelper::register('Apache::lonhelper::dropdown',
@@ -1447,7 +1447,7 @@ sub render {
 # given, switch to it
 sub postprocess {
     my $self = shift;
-    my $chosenValue = $ENV{'form.' . $self->{'variable'} . '.forminput'};
+    my $chosenValue = $env{'form.' . $self->{'variable'} . '.forminput'};
 
     if (!defined($chosenValue) && !$self->{'allowempty'}) {
         $self->{ERROR_MSG} = "You must choose one or more choices to" .
@@ -1506,7 +1506,7 @@ no strict;
 @ISA = ("Apache::lonhelper::element");
 use strict;
 use Apache::lonlocal; # A localization nightmare
-
+use Apache::lonnet;
 use Time::localtime;
 
 BEGIN {
@@ -1650,14 +1650,14 @@ sub render {
 sub postprocess {
     my $self = shift;
     my $var = $self->{'variable'};
-    my $month = $ENV{'form.' . $var . 'month'}; 
-    my $day = $ENV{'form.' . $var . 'day'}; 
-    my $year = $ENV{'form.' . $var . 'year'}; 
+    my $month = $env{'form.' . $var . 'month'}; 
+    my $day = $env{'form.' . $var . 'day'}; 
+    my $year = $env{'form.' . $var . 'year'}; 
     my $min = 0; 
     my $hour = 0;
     if ($self->{'hoursminutes'}) {
-        $min = $ENV{'form.' . $var . 'minute'};
-        $hour = $ENV{'form.' . $var . 'hour'};
+        $min = $env{'form.' . $var . 'minute'};
+        $hour = $env{'form.' . $var . 'hour'};
     }
 
     my $chosenDate;
@@ -1715,7 +1715,9 @@ to false. The "suppressEmptySequences" a
 suppressEmptySequences argument to the render routine, which will cause
 folders that have all of their contained resources filtered out to also
 be filtered out. The 'addstatus' attribute, if true, will add the icon
-and long status display columns to the display.
+and long status display columns to the display. The 'addparts'
+attribute will add in a part selector beside problems that have more
+than 1 part.
 
 =head3 SUB-TAGS
 
@@ -1755,6 +1757,7 @@ and long status display columns to the d
 no strict;
 @ISA = ("Apache::lonhelper::element");
 use strict;
+use Apache::lonnet;
 
 BEGIN {
     &Apache::lonhelper::register('Apache::lonhelper::resource',
@@ -1782,6 +1785,10 @@ sub start_resource {
     $paramHash->{'suppressEmptySequences'} = $token->[2]{'suppressEmptySequences'};
     $paramHash->{'toponly'} = $token->[2]{'toponly'};
     $paramHash->{'addstatus'} = $token->[2]{'addstatus'};
+    $paramHash->{'addparts'} = $token->[2]{'addparts'};
+    if ($paramHash->{'addparts'}) {
+	$helper->declareVar($paramHash->{'variable'}.'_part');
+    }
     $paramHash->{'closeallpages'} = $token->[2]{'closeallpages'};
     return '';
 }
@@ -1955,9 +1962,10 @@ BUTTONS
     my $filterFunc     = $self->{FILTER_FUNC};
     my $choiceFunc     = $self->{CHOICE_FUNC};
     my $valueFunc      = $self->{VALUE_FUNC};
-    my $multichoice   = $self->{'multichoice'};
+    my $multichoice    = $self->{'multichoice'};
     my $option_vars    = $self->{OPTION_VARS};
     my $option_texts   = $self->{OPTION_TEXTS};
+    my $addparts       = $self->{'addparts'};
     my $headings_done  = 0;
 
     # Evaluate the map url as needed
@@ -1970,6 +1978,7 @@ BUTTONS
 	$mapUrl = $self->{MAP_URL};
     }
 
+
     # Create the composite function that renders the column on the nav map
     # have to admit any language that lets me do this can't be all bad
     #  - Jeremy (Pythonista) ;-)
@@ -1998,14 +2007,21 @@ BUTTONS
             return $result;
         } else {
 	    my $col = "";
+	    my $raw_name = &$valueFunc($resource);
 	    my $resource_name =   
-                   HTML::Entities::encode(&$valueFunc($resource),"<>&\"'");
+                   HTML::Entities::encode($raw_name,"<>&\"'");
 	    if($option_vars) {
 		foreach my $option_var (@$option_vars) {
+		    my $var_value = "\|\|\|" . $helper->{VARS}->{$option_var} . 
+			"\|\|\|";
+		    my $checked ="";
+		    if($var_value =~ /\Q|||$raw_name|||\E/) {
+			$checked = "checked";
+		    }
 		    $col .= 
                         "<td align='center'><input type='checkbox' name ='$option_var".
 			".forminput' value='".
-			$resource_name . "' /> </td>";
+			$resource_name . "' $checked /> </td>";
 		}
 	    }
 
@@ -2019,12 +2035,51 @@ BUTTONS
 		$checked = 1;
 	    }
             $col .= "value='" . $resource_name  . "' /></td>";
+
             return $result.$col;
         }
     };
+    my $renderPartsFunc = sub {
+        my ($resource, $part, $params) = @_;
+	my $col= "<td>";
+	my $id=$resource->{ID};
+	my $resource_name =   
+	    &HTML::Entities::encode(&$valueFunc($resource),"<>&\"'");
+	if ($addparts && (scalar(@{$resource->parts}) > 1)) {
+	    $col .= "<select onclick=\"javascript:updateRadio(this.form,'${var}.forminput','$resource_name');updateHidden(this.form,'$id','${var}');\" name='part_$id.forminput'>\n";
+	    $col .= "<option value=\"$part\">All Parts</option>\n";
+	    foreach my $part (@{$resource->parts}) {
+		$col .= "<option value=\"$part\">Part: $part</option>\n";
+	    }
+	    $col .= "</select>";
+	}
+	$col .= "</td>";
+    };
+    $result.=(<<RADIO);
+<script type="text/javascript">
+    function updateRadio(form,name,value) {
+	var radiobutton=form[name];
+	for (var i=0; i<radiobutton.length; i++) {
+	    if (radiobutton[i].value == value) {
+		radiobutton[i].checked = true;
+		break;
+	    }
+	}
+    }
+    function updateHidden(form,id,name) {
+	var select=form['part_'+id+'.forminput'];
+	var hidden=form[name+'_part.forminput'];
+	var which=select.selectedIndex;
+	hidden.value=select.options[which].value;
+    }
+</script>
+<input type="hidden" name="${var}_part.forminput" />
 
-    $ENV{'form.condition'} = !$self->{'toponly'};
-    my $cols = [$renderColFunc, Apache::lonnavmaps::resource()];
+RADIO
+    $env{'form.condition'} = !$self->{'toponly'};
+    my $cols = [$renderColFunc];
+    if ($self->{'addparts'}) { push(@$cols, $renderPartsFunc); }
+    push(@$cols, Apache::lonnavmaps::resource());
     if ($self->{'addstatus'}) {
 	push @$cols, (Apache::lonnavmaps::part_status_summary());
 	
@@ -2101,7 +2156,7 @@ no strict;
 @ISA = ("Apache::lonhelper::element");
 use strict;
 use Apache::lonlocal;
-
+use Apache::lonnet;
 
 BEGIN {
     &Apache::lonhelper::register('Apache::lonhelper::student',
@@ -2124,7 +2179,7 @@ sub start_student {
     $helper->declareVar($paramHash->{'variable'});
     $paramHash->{'multichoice'} = $token->[2]{'multichoice'};
     $paramHash->{'coursepersonnel'} = $token->[2]{'coursepersonnel'};
-    $paramHash->{'sctiveonly'} = $token->[2]{'activeonly'};
+    $paramHash->{'activeonly'} = $token->[2]{'activeonly'};
     if (defined($token->[2]{'nextstate'})) {
         $paramHash->{NEXTSTATE} = $token->[2]{'nextstate'};
     }
@@ -2317,7 +2372,7 @@ BUTTONS
 sub postprocess {
     my $self = shift;
 
-    my $result = $ENV{'form.' . $self->{'variable'} . '.forminput'};
+    my $result = $env{'form.' . $self->{'variable'} . '.forminput'};
     if (!$result) {
         $self->{ERROR_MSG} = 
 	    &mt('You must choose at least one student to continue.');
@@ -2387,7 +2442,7 @@ no strict;
 @ISA = ("Apache::lonhelper::element");
 use strict;
 use Apache::lonlocal;
-
+use Apache::lonnet;
 use Apache::lonpubdir; # for getTitleString
 
 BEGIN {
@@ -2551,7 +2606,7 @@ BUTTONS
         @fileList = &Apache::lonnet::dirlist($subdir, $domain, $user, '');
     } else {
         # local library server resource space
-        @fileList = &Apache::lonnet::dirlist($subdir, $ENV{'user.domain'}, $ENV{'user.name'}, '');
+        @fileList = &Apache::lonnet::dirlist($subdir, $env{'user.domain'}, $env{'user.name'}, '');
     }
 
     # Sort the fileList into order
@@ -2644,9 +2699,9 @@ sub fileState {
     my $constructionSpaceDir = shift;
     my $file = shift;
     
-    my ($uname,$udom)=($ENV{'user.name'},$ENV{'user.domain'});
-    if ($ENV{'request.role'}=~/^ca\./) {
-	(undef,$udom,$uname)=split(/\//,$ENV{'request.role'});
+    my ($uname,$udom)=($env{'user.name'},$env{'user.domain'});
+    if ($env{'request.role'}=~/^ca\./) {
+	(undef,$udom,$uname)=split(/\//,$env{'request.role'});
     }
     my $docroot = $Apache::lonnet::perlvar{'lonDocRoot'};
     my $subdirpart = $constructionSpaceDir;
@@ -2671,7 +2726,7 @@ sub fileState {
 
 sub postprocess {
     my $self = shift;
-    my $result = $ENV{'form.' . $self->{'variable'} . '.forminput'};
+    my $result = $env{'form.' . $self->{'variable'} . '.forminput'};
     if (!$result) {
         $self->{ERROR_MSG} = 'You must choose at least one file '.
             'to continue.';
@@ -2824,7 +2879,7 @@ sub render {
     my $result = '';
 
     if (defined $self->{ERROR_MSG}) {
-        $result .= '<br /><font color="#FF0000">' . $self->{ERROR_MSG} . '</font><br /><br />';
+        $result .= '<p><font color="#FF0000">' . $self->{ERROR_MSG} . '</font></p>';
     }
 
     $result .= '<input type="string" name="' . $self->{'variable'} . '.forminput"';
@@ -2878,7 +2933,7 @@ package Apache::lonhelper::general;
 =head2 General-purpose tag: <exec>X<exec, helper tag>
 
 The contents of the exec tag are executed as Perl code, B<not> inside a 
-safe space, so the full range of $ENV and such is available. The code
+safe space, so the full range of $env and such is available. The code
 will be executed as a subroutine wrapped with the following code:
 
 "sub { my $helper = shift; my $state = shift;" and
@@ -2900,6 +2955,7 @@ be able to call methods on it.
 =cut
 
 use Apache::lonlocal;
+use Apache::lonnet;
 
 BEGIN {
     &Apache::lonhelper::register('Apache::lonhelper::general',
@@ -3022,12 +3078,16 @@ will make a "Finish Helper" button that
 which is useful for the Course Initialization helper so the users never see
 the old values taking effect.
 
+If the parameter "restartCourse" is not true a 'Finish' Button will be
+presented that takes the user back to whatever was defined as <exitpage>
+
 =cut
 
 no strict;
 @ISA = ("Apache::lonhelper::element");
 use strict;
 use Apache::lonlocal;
+use Apache::lonnet;
 BEGIN {
     &Apache::lonhelper::register('Apache::lonhelper::final',
                                  ('final', 'exitpage'));
@@ -3119,35 +3179,38 @@ sub render {
 	$result .= '</ul>';
     }
 
+    my $actionURL = $self->{EXIT_PAGE};
+    my $targetURL = '';
+    my $finish=&mt('Finish');
     if ($self->{'restartCourse'}) {
-	my $targetURL = '/adm/menu';
-	if ($ENV{'course.'.$ENV{'request.course.id'}.'.url'}=~/^uploaded/) {
+	my $actionURL = '/adm/roles';
+	$targetURL = '/adm/menu';
+	if ($env{'course.'.$env{'request.course.id'}.'.url'}=~/^uploaded/) {
 	    $targetURL = '/adm/coursedocs';
 	} else {
 	    $targetURL = '/adm/navmaps';
 	}
-	if ($ENV{'course.'.$ENV{'request.course.id'}.'.clonedfrom'}) {
+	if ($env{'course.'.$env{'request.course.id'}.'.clonedfrom'}) {
 	    $targetURL = '/adm/parmset?overview=1';
 	}
-	my $previous = HTML::Entities::encode(&mt("<- Previous"), '<>&"');
-	my $next = HTML::Entities::encode(&mt("Next ->"), '<>&"');
-        $result .= "<center>\n" .
-            "<form action='/adm/roles' method='post' target='loncapaclient'>\n" .
-            "<input type='button' onclick='history.go(-1)' value='$previous' />" .
-            "<input type='hidden' name='orgurl' value='$targetURL' />" .
-            "<input type='hidden' name='selectrole' value='1' />\n" .
-            "<input type='hidden' name='" . $ENV{'request.role'} . 
-            "' value='1' />\n<input type='submit' value='" .
-	    &mt('Finish Course Initialization') . "' />\n" .
-            "</form></center>";
+	my $finish=&mt('Finish Course Initialization');
     }
+    my $previous = HTML::Entities::encode(&mt("<- Previous"), '<>&"');
+    my $next = HTML::Entities::encode(&mt("Next ->"), '<>&"');
+    $result .= "<center>\n" .
+	"<form action='".$actionURL."' method='post' target='loncapaclient'>\n" .
+	"<input type='button' onclick='history.go(-1)' value='$previous' />" .
+	"<input type='hidden' name='orgurl' value='$targetURL' />" .
+	"<input type='hidden' name='selectrole' value='1' />\n" .
+	"<input type='hidden' name='" . $env{'request.role'} . 
+	"' value='1' />\n<input type='submit' value='" . $finish . "' />\n" .
+	"</form></center>";
 
     return $result;
 }
 
 sub overrideForm {
-    my $self = shift;
-    return $self->{'restartCourse'};
+    return 1;
 }
 
 1;
@@ -3163,6 +3226,7 @@ no strict;
 @ISA = ('Apache::lonhelper::element');
 use strict;
 use Apache::lonlocal;
+use Apache::lonnet;
 
 BEGIN {
     &Apache::lonhelper::register('Apache::lonhelper::parmwizfinal',
@@ -3211,7 +3275,7 @@ sub render {
     my $resourceString;
     my $symb;
     my $paramlevel;
-
+    
     # Print the granularity, depending on the action
     if ($vars->{GRANULARITY} eq 'whole_course') {
         $resourceString .= '<li>'.&mt('for <b>all resources in the course</b>').'</li>';
@@ -3231,15 +3295,27 @@ sub render {
     } else {
         my $navmap = Apache::lonnavmaps::navmap->new();
         my $res = $navmap->getById($vars->{RESOURCE_ID});
+        my $part = $vars->{RESOURCE_ID_part};
+	if ($part ne 'All Parts' && $part) { $parm_name=~s/^0/$part/; } else { $part=&mt('All Parts'); }
         $symb = $res->symb();
         my $title = $res->compTitle();
-        $resourceString .= '<li>'.&mt('for the resource named [_1]',"<b>$title</b>").'</li>';
+        $resourceString .= '<li>'.&mt('for the resource named [_1] part [_2]',"<b>$title</b>","<b>$part</b>").'</li>';
         $level = 7;
         $affectedResourceId = $vars->{RESOURCE_ID};
         $paramlevel = 'full';
     }
 
     my $result = "<form name='helpform' method='get' action='/adm/parmset#$affectedResourceId&$parm_name&$level'>\n";
+    if ($vars->{GRANULARITY} eq 'resource') {
+	$result .= "<input type='hidden' name='symb' value='".
+	    HTML::Entities::encode($symb,"'<>&\"") . "' />\n";
+	$result .= "<input type='hidden' name='pscat' value='".
+	    HTML::Entities::encode($vars->{ACTION_TYPE},"'<>&\"") . "' />\n";
+	my $part = $vars->{RESOURCE_ID_part};
+	if ($part eq 'All Parts' || !$part) { $part=0; }
+	$result .= "<input type='hidden' name='psprt' value='".
+	    HTML::Entities::encode($part,"'<>&\"") . "' />\n";
+    }
     $result .= '<p>'.&mt('Confirm that this information is correct, then click &quot;Finish Helper&quot; to complete setting the parameter.').'<ul>';
     
     # Print the type of manipulation: