--- loncom/interface/lonhelper.pm 2005/07/07 04:19:20 1.107 +++ loncom/interface/lonhelper.pm 2006/05/30 12:46:09 1.152 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # .helper XML handler to implement the LON-CAPA helper # -# $Id: lonhelper.pm,v 1.107 2005/07/07 04:19:20 albertel Exp $ +# $Id: lonhelper.pm,v 1.152 2006/05/30 12:46:09 www Exp $ # # Copyright Michigan State University Board of Trustees # @@ -183,6 +183,10 @@ use Apache::File; use Apache::lonxml; use Apache::lonlocal; use Apache::lonnet; +use Apache::longroup; +use Apache::lonselstudent; +use lib '/home/httpd/lib/perl/'; +use LONCAPA; # Register all the tags with the helper, so the helper can # push and pop them @@ -467,8 +471,8 @@ sub _varsInFile { my $self = shift; my @vars = (); for my $key (keys %{$self->{VARS}}) { - push @vars, &Apache::lonnet::escape($key) . '=' . - &Apache::lonnet::escape($self->{VARS}->{$key}); + push @vars, &escape($key) . '=' . + &escape($self->{VARS}->{$key}); } return join ('&', @vars); } @@ -573,22 +577,20 @@ 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,'',''); + my $browser_searcher_js = + '<script type="text/javascript">'."\n". + &Apache::loncommon::browser_and_searcher_javascript(). + "\n".'</script>'; + + $result .= &Apache::loncommon::start_page($self->{TITLE}, + $browser_searcher_js); + my $previous = HTML::Entities::encode(&mt("<- Previous"), '<>&"'); my $next = HTML::Entities::encode(&mt("Next ->"), '<>&"'); # FIXME: This should be parameterized, not concatenated - Jeremy - my $loncapaHelper = &mt("LON-CAPA Helper:"); - $result .= <<HEADER; -$html - <head> - <title>$loncapaHelper: $helperTitle</title> - </head> - $bodytag -HEADER + if (!$state->overrideForm()) { $result.="<form name='helpform' method='POST'>"; } $result .= <<HEADER; <table border="0" width='100%'><tr><td> @@ -651,10 +653,9 @@ HEADER </tr> </table> </form> - </body> -</html> FOOTER + $result .= &Apache::loncommon::end_page(); # Handle writing out the vars to the file my $file = Apache::File->new('>'.$self->{FILENAME}); print $file $self->_varsInFile(); @@ -1072,6 +1073,16 @@ will be the state transistioned to if th the choice is not multichoice. This will override the nextstate passed to the parent C<choices> tag. +<choice> may optionally contain a 'relatedvalue' attribute, which +if present will cause a text entry to appear to the right of the +selection. The value of the relatedvalue attribute is a variable +into which the text entry will be stored e.g.: +<choice computer='numberprovided" relatedvalue="num">Type the number in:</choice> + +<choice> may contain a relatededefault atribute which, if the +relatedvalue attribute is present will be the initial value of the input +box. + =back To create the choices programmatically, either wrap the choices in @@ -1162,10 +1173,12 @@ sub start_choice { my $computer = $token->[2]{'computer'}; my $human = &mt(&Apache::lonxml::get_all_text('/choice', $parser)); - my $nextstate = $token->[2]{'nextstate'}; - my $evalFlag = $token->[2]{'eval'}; + my $nextstate = $token->[2]{'nextstate'}; + my $evalFlag = $token->[2]{'eval'}; + my $relatedVar = $token->[2]{'relatedvalue'}; + my $relatedDefault = $token->[2]{'relateddefault'}; push @{$paramHash->{CHOICES}}, [&mtn($human), $computer, $nextstate, - $evalFlag]; + $evalFlag, $relatedVar, $relatedDefault]; return ''; } @@ -1188,7 +1201,8 @@ sub render { if ($self->{'multichoice'}) { $result .= <<SCRIPT; -<script> +<script type="text/javascript"> +// <!-- function checkall(value, checkName) { for (i=0; i<document.forms.helpform.elements.length; i++) { ele = document.forms.helpform.elements[i]; @@ -1197,6 +1211,7 @@ sub render { } } } +// --> </script> SCRIPT } @@ -1265,22 +1280,28 @@ BUTTONS my $id = &new_id(); $result .= "<tr>\n<td width='20'> </td>\n"; $result .= "<td valign='top'><input type='$type' name='$var.forminput'" - . "' value='" . + . " value='" . HTML::Entities::encode($choice->[1],"<>&\"'") . "'"; if ($checkedChoices{$choice->[1]}) { - $result .= " checked "; + $result .= " checked='checked' "; } - $result .= qq{id="$id"}; + $result .= qq{id="id$id"}; my $choiceLabel = $choice->[0]; - if ($choice->[4]) { # if we need to evaluate this choice + if ($choice->[3]) { # if we need to evaluate this choice $choiceLabel = "sub { my $helper = shift; my $state = shift;" . $choiceLabel . "}"; $choiceLabel = eval($choiceLabel); $choiceLabel = &$choiceLabel($helper, $self); } - $result .= "/></td><td> ".qq{<label for="$id">}. - $choiceLabel. "</label></td></tr>\n"; + $result .= "/></td><td> ".qq{<label for="id$id">}. + $choiceLabel. "</label></td>"; + if ($choice->[4]) { + $result .='<td><input type="text" size="5" name="' + .$choice->[4].'.forminput" value="' + .$choice->[5].'" /></td>'; + } + $result .= "</tr>\n"; } $result .= "</table>\n\n\n"; $result .= $buttons; @@ -1314,6 +1335,10 @@ sub postprocess { $helper->changeState($choice->[2]); } } + if ($choice->[4]) { + my $varname = $choice->[4]; + $helper->{'VARS'}->{$varname} = $env{'form.'."$varname.forminput"}; + } } return 1; } @@ -1427,7 +1452,7 @@ sub render { HTML::Entities::encode($choice->[1],"<>&\"'") . "'"; if ($checkedChoices{$choice->[1]}) { - $result .= " selected"; + $result .= " selected='selected' "; } my $choiceLabel = $choice->[0]; if ($choice->[4]) { # if we need to evaluate this choice @@ -1436,7 +1461,7 @@ sub render { $choiceLabel = eval($choiceLabel); $choiceLabel = &$choiceLabel($helper, $self); } - $result .= ">" . &mtn($choiceLabel) . "\n"; + $result .= ">" . &mtn($choiceLabel) . "</option>\n"; } $result .= "</select>\n"; @@ -1534,6 +1559,7 @@ sub start_date { $paramHash->{'variable'} = $token->[2]{'variable'}; $helper->declareVar($paramHash->{'variable'}); $paramHash->{'hoursminutes'} = $token->[2]{'hoursminutes'}; + $paramHash->{'anytime'} = $token->[2]{'anytime'}; } sub end_date { @@ -1552,10 +1578,45 @@ sub render { my $var = $self->{'variable'}; my $date; - + + my $time=time; + my ($anytime,$onclick); + + + # first check VARS for a valid new value from the user + # then check DEFAULT_VALUE for a valid default time value + # otherwise pick now as reasonably good time + + if (defined($helper->{VARS}{$var}) + && $helper->{VARS}{$var} > 0) { + $date = localtime($helper->{VARS}{$var}); + } elsif (defined($self->{DEFAULT_VALUE})) { + my $valueFunc = eval($self->{DEFAULT_VALUE}); + die('Error in default value code for variable ' . + $self->{'variable'} . ', Perl said: ' . $@) if $@; + $time = &$valueFunc($helper, $self); + if (lc($time) eq 'anytime') { + $anytime=1; + $date = localtime(time); + $date->min(0); + } elsif (defined($time) && $time ne 0) { + $date = localtime($time); + } else { + # leave date undefined so it'll default to now + } + } + + if (!defined($date)) { + $date = localtime(time); + $date->min(0); + } + + &Apache::lonnet::logthis("date mode "); + + if ($anytime) { + $onclick = "onclick=\"javascript:updateCheck(this.form,'${var}anytime',false)\""; + } # Default date: The current hour. - $date = localtime(); - $date->min(0); if (defined $self->{ERROR_MSG}) { $result .= '<font color="#FF0000">' . $self->{ERROR_MSG} . '</font><br /><br />'; @@ -1563,10 +1624,10 @@ sub render { # Month my $i; - $result .= "<select name='${var}month'>\n"; + $result .= "<select $onclick name='${var}month'>\n"; for ($i = 0; $i < 12; $i++) { if ($i == $date->mon) { - $result .= "<option value='$i' selected>"; + $result .= "<option value='$i' selected='selected'>"; } else { $result .= "<option value='$i'>"; } @@ -1575,10 +1636,10 @@ sub render { $result .= "</select>\n"; # Day - $result .= "<select name='${var}day'>\n"; + $result .= "<select $onclick name='${var}day'>\n"; for ($i = 1; $i < 32; $i++) { if ($i == $date->mday) { - $result .= '<option selected>'; + $result .= '<option selected="selected">'; } else { $result .= '<option>'; } @@ -1587,10 +1648,10 @@ sub render { $result .= "</select>,\n"; # Year - $result .= "<select name='${var}year'>\n"; + $result .= "<select $onclick name='${var}year'>\n"; for ($i = 2000; $i < 2030; $i++) { # update this after 64-bit dates if ($date->year + 1900 == $i) { - $result .= "<option selected>"; + $result .= "<option selected='selected'>"; } else { $result .= "<option>"; } @@ -1604,22 +1665,22 @@ sub render { my $am = &mt('a.m.'); my $pm = &mt('p.m.'); # Build hour - $result .= "<select name='${var}hour'>\n"; - $result .= "<option " . ($date->hour == 0 ? 'selected ':'') . + $result .= "<select $onclick name='${var}hour'>\n"; + $result .= "<option " . ($date->hour == 0 ? 'selected="selected" ':'') . " value='0'>" . &mt('midnight') . "</option>\n"; for ($i = 1; $i < 12; $i++) { if ($date->hour == $i) { - $result .= "<option selected value='$i'>$i $am</option>\n"; + $result .= "<option selected='selected' value='$i'>$i $am</option>\n"; } else { $result .= "<option value='$i'>$i $am</option>\n"; } } - $result .= "<option " . ($date->hour == 12 ? 'selected ':'') . + $result .= "<option " . ($date->hour == 12 ? 'selected="selected" ':'') . " value='12'>" . &mt('noon') . "</option>\n"; for ($i = 13; $i < 24; $i++) { my $printedHour = $i - 12; if ($date->hour == $i) { - $result .= "<option selected value='$i'>$printedHour $pm</option>\n"; + $result .= "<option selected='selected' value='$i'>$printedHour $pm</option>\n"; } else { $result .= "<option value='$i'>$printedHour $pm</option>\n"; } @@ -1627,14 +1688,16 @@ sub render { $result .= "</select> :\n"; - $result .= "<select name='${var}minute'>\n"; - for ($i = 0; $i < 60; $i++) { + $result .= "<select $onclick name='${var}minute'>\n"; + my $selected=0; + for my $i ((0,15,30,45,59,undef,0..59)) { my $printedMinute = $i; - if ($i < 10) { + if (defined($i) && $i < 10) { $printedMinute = "0" . $printedMinute; } - if ($date->min == $i) { - $result .= "<option selected>"; + if (!$selected && $date->min == $i) { + $result .= "<option selected='selected'>"; + $selected=1; } else { $result .= "<option>"; } @@ -1642,7 +1705,23 @@ sub render { } $result .= "</select>\n"; } - + if ($self->{'anytime'}) { + $result.=(<<CHECK); +<script type="text/javascript"> +// <!-- + function updateCheck(form,name,value) { + var checkbox=form[name]; + checkbox.checked = value; + } +// --> +</script> +CHECK + $result.=" or <label><input type='checkbox' "; + if ($anytime) { + $result.=' checked="checked" ' + } + $result.="name='${var}anytime'/>".&mt('Any time').'</label>' + } return $result; } @@ -1650,40 +1729,53 @@ 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 $min = 0; - my $hour = 0; - if ($self->{'hoursminutes'}) { - $min = $env{'form.' . $var . 'minute'}; - $hour = $env{'form.' . $var . 'hour'}; - } + if ($env{'form.' . $var . 'anytime'}) { + $helper->{VARS}->{$var} = undef; + } else { + 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'}; + } + + my $chosenDate; + eval {$chosenDate = Time::Local::timelocal(0, $min, $hour, $day, $month, $year);}; + my $error = $@; + + # Check to make sure that the date was not automatically co-erced into a + # valid date, as we want to flag that as an error + # This happens for "Feb. 31", for instance, which is coerced to March 2 or + # 3, depending on if it's a leap year + my $checkDate = localtime($chosenDate); + + if ($error || $checkDate->mon != $month || $checkDate->mday != $day || + $checkDate->year + 1900 != $year) { + unless (Apache::lonlocal::current_language()== ~/^en/) { + $self->{ERROR_MSG} = &mt("Invalid date entry"); + return 0; + } + # LOCALIZATION FIXME: Needs to be parameterized + $self->{ERROR_MSG} = "Can't use " . $months[$month] . " $day, $year as a " + . "date because it doesn't exist. Please enter a valid date."; - my $chosenDate; - eval {$chosenDate = Time::Local::timelocal(0, $min, $hour, $day, $month, $year);}; - my $error = $@; - - # Check to make sure that the date was not automatically co-erced into a - # valid date, as we want to flag that as an error - # This happens for "Feb. 31", for instance, which is coerced to March 2 or - # 3, depending on if it's a leap year - my $checkDate = localtime($chosenDate); - - if ($error || $checkDate->mon != $month || $checkDate->mday != $day || - $checkDate->year + 1900 != $year) { - unless (Apache::lonlocal::current_language()== ~/^en/) { - $self->{ERROR_MSG} = &mt("Invalid date entry"); return 0; } - # LOCALIZATION FIXME: Needs to be parameterized - $self->{ERROR_MSG} = "Can't use " . $months[$month] . " $day, $year as a " - . "date because it doesn't exist. Please enter a valid date."; - - return 0; + $helper->{VARS}->{$var} = $chosenDate; } - $helper->{VARS}->{$var} = $chosenDate; + if (defined($self->{VALIDATOR})) { + my $validator = eval($self->{VALIDATOR}); + die 'Died during evaluation of validator code; Perl said: ' . $@ if $@; + my $invalid = &$validator($helper, $state, $self, $self->getValue()); + if ($invalid) { + $self->{ERROR_MSG} = $invalid; + return 0; + } + } if (defined($self->{NEXTSTATE})) { $helper->changeState($self->{NEXTSTATE}); @@ -1930,7 +2022,8 @@ sub render { if ($self->{'multichoice'}) { $result = <<SCRIPT; -<script> +<script type="text/javascript"> +// <!-- function checkall(value, checkName) { for (i=0; i<document.forms.helpform.elements.length; i++) { ele = document.forms.helpform.elements[i]; @@ -1939,6 +2032,7 @@ sub render { } } } +// --> </script> SCRIPT my %lt=&Apache::lonlocal::texthash( @@ -1978,6 +2072,18 @@ BUTTONS $mapUrl = $self->{MAP_URL}; } + my %defaultSymbs; + if (defined($self->{DEFAULT_VALUE})) { + my $valueFunc = eval($self->{DEFAULT_VALUE}); + die 'Error in default value code for variable ' . + $self->{'variable'} . ', Perl said: ' . $@ if $@; + my @defaultSymbs = &$valueFunc($helper, $self); + if (!$multichoice && @defaultSymbs) { # only allowed 1 + @defaultSymbs = ($defaultSymbs[0]); + } + %defaultSymbs = map { if ($_) {($_,1) } } @defaultSymbs; + delete($defaultSymbs{''}); + } # 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 @@ -2016,7 +2122,7 @@ BUTTONS "\|\|\|"; my $checked =""; if($var_value =~ /\Q|||$raw_name|||\E/) { - $checked = "checked"; + $checked = "checked='checked'"; } $col .= "<td align='center'><input type='checkbox' name ='$option_var". @@ -2026,13 +2132,21 @@ BUTTONS } $col .= "<td align='center'><input type='$inputType' name='${var}.forminput' "; - if (!$checked && !$multichoice) { - $col .= "checked "; - $checked = 1; - } - if ($multichoice) { # all resources start checked; see bug 1174 - $col .= "checked "; - $checked = 1; + if (%defaultSymbs) { + my $symb=$resource->symb(); + if (exists($defaultSymbs{$symb})) { + $col .= "checked='checked' "; + $checked = 1; + } + } else { + if (!$checked && !$multichoice) { + $col .= "checked='checked' "; + $checked = 1; + } + if ($multichoice) { # all resources start checked; see bug 1174 + $col .= "checked='checked' "; + $checked = 1; + } } $col .= "value='" . $resource_name . "' /></td>"; @@ -2057,6 +2171,7 @@ BUTTONS }; $result.=(<<RADIO); <script type="text/javascript"> +// <!-- function updateRadio(form,name,value) { var radiobutton=form[name]; for (var i=0; i<radiobutton.length; i++) { @@ -2072,6 +2187,7 @@ BUTTONS var which=select.selectedIndex; hidden.value=select.options[which].value; } +// --> </script> <input type="hidden" name="${var}_part.forminput" /> @@ -2148,6 +2264,10 @@ selection. Defaults to false. If true, only active students and course personnel will be shown. Defaults to false. +=item * B<emptyallowed>: + +If true, the selection of no users is allowed. Defaults to false. + =back =cut @@ -2183,6 +2303,7 @@ sub start_student { if (defined($token->[2]{'nextstate'})) { $paramHash->{NEXTSTATE} = $token->[2]{'nextstate'}; } + $paramHash->{'emptyallowed'} = $token->[2]{'emptyallowed'}; } @@ -2201,171 +2322,76 @@ sub render { my $buttons = ''; my $var = $self->{'variable'}; - if ($self->{'multichoice'}) { - $result = <<SCRIPT; -<script> - function checkall(value, checkName) { - for (i=0; i<document.forms.helpform.elements.length; i++) { - ele = document.forms.helpform.elements[i]; - if (ele.name == checkName + '.forminput') { - document.forms.helpform.elements[i].checked=value; - } - } - } - function checksec(value) { - for (i=0; i<document.forms.helpform.elements.length; i++) { - comp = document.forms.helpform.elements.chksec.value; - if (document.forms.helpform.elements[i].value.indexOf(':'+comp+':') != -1) { - if (document.forms.helpform.elements[i].value.indexOf(':Active') != -1) { - document.forms.helpform.elements[i].checked=value; - } - } - } - } - function checkactive() { - for (i=0; i<document.forms.helpform.elements.length; i++) { - if (document.forms.helpform.elements[i].value.indexOf(':Active') != -1) { - document.forms.helpform.elements[i].checked=true; - } - } - } - function uncheckexpired() { - for (i=0; i<document.forms.helpform.elements.length; i++) { - if (document.forms.helpform.elements[i].value.indexOf(':Expired') != -1) { - document.forms.helpform.elements[i].checked=false; - } - } - } -</script> -SCRIPT - - my %lt=&Apache::lonlocal::texthash( - 'ocs' => "Select Only Current Students", - 'ues' => "Unselect Expired Students", - 'sas' => "Select All Students", - 'uas' => "Unselect All Students", - 'sfsg' => "Select Current Students for Section/Group", - 'ufsg' => "Unselect for Section/Group"); - - $buttons = <<BUTTONS; -<br /> -<table> - <tr> - - <td><input type="button" onclick="checkactive()" value="$lt{'ocs'}" /></td> - <td><input type="button" onclick="uncheckexpired()" value="$lt{'ues'}" /><br /></td> - </tr> - <tr> - <td><input type="button" onclick="checkall(true, '$var')" value="$lt{'sas'}" /></td> - <td> <input type="button" onclick="checkall(false, '$var')" value="$lt{'uas'}" /><br /></td> - </tr> - <tr> - <td><input type="button" onclick="checksec(true)" value="$lt{'sfsg'}"></td> - <td><input type="text" size="5" name="chksec"> </td> - </tr> - <tr> - <td><input type="button" onclick="checksec(false)" value="$lt{'ufsg'}"></td> - <td></td> - </tr> -</table> -<br /> -BUTTONS - } if (defined $self->{ERROR_MSG}) { $result .= '<font color="#FF0000">' . $self->{ERROR_MSG} . '</font><br /><br />'; } - my $choices = []; + my %defaultUsers; + if (defined($self->{DEFAULT_VALUE})) { + my $valueFunc = eval($self->{DEFAULT_VALUE}); + die 'Error in default value code for variable ' . + $self->{'variable'} . ', Perl said: ' . $@ if $@; + my @defaultUsers = &$valueFunc($helper, $self); + if (!$self->{'multichoice'} && @defaultUsers) { # only allowed 1 + @defaultUsers = ($defaultUsers[0]); + } + %defaultUsers = map { if ($_) {($_,1) } } @defaultUsers; + delete($defaultUsers{''}); + } + + + my ($course_personnel, + $current_members, + $expired_members, + $future_members) = &Apache::lonselstudent::get_people_in_class(); + + # Load up the non-students, if necessary + if ($self->{'coursepersonnel'}) { - my %coursepersonnel = Apache::lonnet::get_course_adv_roles(); - for (sort keys %coursepersonnel) { - for my $role (split /,/, $coursepersonnel{$_}) { - # extract the names so we can sort them - my @people; - - for (split /,/, $role) { - push @people, [split /:/, $role]; - } - - @people = sort { $a->[0] cmp $b->[0] } @people; - - for my $person (@people) { - push @$choices, [join(':', @$person), $person->[0], '', $_]; - } - } - } + unshift @$current_members, (@$course_personnel); } - # Constants - my $section = Apache::loncoursedata::CL_SECTION(); - my $fullname = Apache::loncoursedata::CL_FULLNAME(); - my $status = Apache::loncoursedata::CL_STATUS(); - # Load up the students - my $classlist = &Apache::loncoursedata::get_classlist(); - my @keys = keys %{$classlist}; - # Sort by: Section, name - @keys = sort { - if ($classlist->{$a}->[$section] ne $classlist->{$b}->[$section]) { - return $classlist->{$a}->[$section] cmp $classlist->{$b}->[$section]; - } - return $classlist->{$a}->[$fullname] cmp $classlist->{$b}->[$fullname]; - } @keys; - - # username, fullname, section, type - for (@keys) { - # Filter out inactive students if we've set "activeonly" - if (!$self->{'activeonly'} || $classlist->{$_}->[$status] eq - 'Active') { - push @$choices, [$_, $classlist->{$_}->[$fullname], - $classlist->{$_}->[$section], - $classlist->{$_}->[$status], 'Student']; - } - } + # Current personel - my $name = $self->{'coursepersonnel'} ? &mt('Name') : &mt('Student Name'); - my $type = 'radio'; - if ($self->{'multichoice'}) { $type = 'checkbox'; } - $result .= "<table cellspacing='2' cellpadding='2' border='0'>\n"; - $result .= "<tr><td></td><td align='center'><b>$name</b></td>". - "<td align='center'><b>" . &mt('Section') . "</b></td>" . - "<td align='center'><b>".&mt('Status')."</b></td>" . - "<td align='center'><b>" . &mt("Role") . "</b></td>" . - "<td align='center'><b>".&mt('Username').":".&mt('Domain')."</b></td></tr>"; + $result .= &Apache::lonselstudent::render_student_list( $current_members, + "helpform", + "current", + \%defaultUsers, + $self->{'multichoice'}, + $self->{'variable'}, + 1); - my $checked = 0; - for my $choice (@$choices) { - $result .= "<tr><td><input type='$type' name='" . - $self->{'variable'} . '.forminput' . "'"; - - if (!$self->{'multichoice'} && !$checked) { - $result .= " checked "; - $checked = 1; - } - $result .= - " value='" . HTML::Entities::encode($choice->[0] . ':' - .$choice->[2] . ':' - .$choice->[1] . ':' - .$choice->[3], "<>&\"'") - . "' /></td><td>" - . HTML::Entities::encode($choice->[1],'<>&"') - . "</td><td align='center'>" - . HTML::Entities::encode($choice->[2],'<>&"') - . "</td>\n<td>" - . HTML::Entities::encode($choice->[3],'<>&"') - . "</td>\n<td>" - . HTML::Entities::encode($choice->[4],'<>&"') - . "</td>\n<td>" - . HTML::Entities::encode($choice->[0],'<>&"') - . "</td></tr>\n"; + + # If activeonly is not set then we can also give the expired students: + # + if (!$self->{'activeonly'} && ((scalar @$expired_members) > 0)) { + + # And future. + + $result .= &Apache::lonselstudent::render_student_list( $future_members, + "helpform", + "future", + \%defaultUsers, + $self->{'multichoice'}, + $self->{'variable'}, + 0); + # Past + + $result .= &Apache::lonselstudent::render_student_list($expired_members, + "helpform", + "past", + \%defaultUsers, + $self->{'multichoice'}, + $self->{'variable'}, + 0); } - $result .= "</table>\n\n"; - $result .= $buttons; - + + return $result; } @@ -2373,9 +2399,14 @@ sub postprocess { my $self = shift; my $result = $env{'form.' . $self->{'variable'} . '.forminput'}; - if (!$result) { - $self->{ERROR_MSG} = - &mt('You must choose at least one student to continue.'); + if (!$result && !$self->{'emptyallowed'}) { + if ($self->{'coursepersonnel'}) { + $self->{ERROR_MSG} = + &mt('You must choose at least one user to continue.'); + } else { + $self->{ERROR_MSG} = + &mt('You must choose at least one student to continue.'); + } return 0; } @@ -2547,7 +2578,8 @@ sub render { if ($self->{'multichoice'}) { $result = <<SCRIPT; -<script> +<script type="text/javascript"> +// <!-- function checkall(value, checkName) { for (i=0; i<document.forms.helpform.elements.length; i++) { ele = document.forms.helpform.elements[i]; @@ -2565,6 +2597,7 @@ sub render { } } } +// --> </script> SCRIPT my %lt=&Apache::lonlocal::texthash( @@ -2594,14 +2627,16 @@ BUTTONS # If the subdirectory is in local CSTR space my $metadir; if ($subdir =~ m|/home/([^/]+)/public_html/(.*)|) { - my $user = $1; - my $domain = $Apache::lonnet::perlvar{'lonDefDomain'}; + my ($user,$domain)= + &Apache::loncacc::constructaccess($subdir, + $Apache::lonnet::perlvar{'lonDefDomain'}); $metadir='/res/'.$domain.'/'.$user.'/'.$2; @fileList = &Apache::lonnet::dirlist($subdir, $domain, $user, ''); } elsif ($subdir =~ m|^~([^/]+)/(.*)$|) { $subdir='/home/'.$1.'/public_html/'.$2; - my $user = $1; - my $domain = $Apache::lonnet::perlvar{'lonDefDomain'}; + my ($user,$domain)= + &Apache::loncacc::constructaccess($subdir, + $Apache::lonnet::perlvar{'lonDefDomain'}); $metadir='/res/'.$domain.'/'.$user.'/'.$2; @fileList = &Apache::lonnet::dirlist($subdir, $domain, $user, ''); } else { @@ -2668,7 +2703,7 @@ BUTTONS . ".forminput' ".qq{id="$id"}." value='" . HTML::Entities::encode($fileName,"<>&\"'"). "'"; if (!$self->{'multichoice'} && $choices == 0) { - $result .= ' checked'; + $result .= ' checked="checked"'; } $result .= "/></td><td bgcolor='$color'>". qq{<label for="$id">}. $file . "</label></td>" . @@ -2751,8 +2786,12 @@ package Apache::lonhelper::section; <section> allows the user to choose one or more sections from the current course. -It takes the standard attributes "variable", "multichoice", and -"nextstate", meaning what they do for most other elements. +It takes the standard attributes "variable", "multichoice", +"allowempty" and "nextstate", meaning what they do for most other +elements. + +also takes a boolean 'onlysections' whcih will restrict this to only +have sections and not include groups =cut @@ -2782,6 +2821,7 @@ sub start_section { $paramHash->{'variable'} = $token->[2]{'variable'}; $helper->declareVar($paramHash->{'variable'}); $paramHash->{'multichoice'} = $token->[2]{'multichoice'}; + $paramHash->{'allowempty'} = $token->[2]{'allowempty'}; if (defined($token->[2]{'nextstate'})) { $paramHash->{NEXTSTATE} = $token->[2]{'nextstate'}; } @@ -2791,18 +2831,29 @@ sub start_section { my $section = Apache::loncoursedata::CL_SECTION(); my $classlist = Apache::loncoursedata::get_classlist(); - foreach (keys %$classlist) { - my $sectionName = $classlist->{$_}->[$section]; - if (!$sectionName) { + foreach my $user (keys(%$classlist)) { + my $section_name = $classlist->{$user}[$section]; + if (!$section_name) { $choices{"No section assigned"} = ""; } else { - $choices{$sectionName} = $sectionName; + $choices{$section_name} = $section_name; } } - for my $sectionName (sort(keys(%choices))) { - - push @{$paramHash->{CHOICES}}, [$sectionName, $sectionName]; + if (exists($choices{"No section assigned"})) { + push(@{$paramHash->{CHOICES}}, + ['No section assigned','No section assigned']); + delete($choices{"No section assigned"}); + } + for my $section_name (sort {lc($a) cmp lc($b) } (keys(%choices))) { + push @{$paramHash->{CHOICES}}, [$section_name, $section_name]; + } + return if ($token->[2]{'onlysections'}); + + # add in groups to the end of the list + my %curr_groups = &Apache::longroup::coursegroups(); + foreach my $group_name (sort(keys(%curr_groups))) { + push(@{$paramHash->{CHOICES}}, [$group_name, $group_name]); } } @@ -2816,6 +2867,70 @@ sub end_section { } 1; +package Apache::lonhelper::group; + +=pod + +=head2 Element: groupX<group, helper element> + +<group> allows the user to choose one or more groups from the current course. + +It takes the standard attributes "variable", "multichoice", + "allowempty" and "nextstate", meaning what they do for most other + elements. + +=cut + +no strict; +@ISA = ("Apache::lonhelper::choices"); +use strict; + +BEGIN { + &Apache::lonhelper::register('Apache::lonhelper::group', + ('group')); +} + +sub new { + my $ref = Apache::lonhelper::choices->new(); + bless($ref); +} + +sub start_group { + my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; + + if ($target ne 'helper') { + return ''; + } + + $paramHash->{CHOICES} = []; + + $paramHash->{'variable'} = $token->[2]{'variable'}; + $helper->declareVar($paramHash->{'variable'}); + $paramHash->{'multichoice'} = $token->[2]{'multichoice'}; + $paramHash->{'allowempty'} = $token->[2]{'allowempty'}; + if (defined($token->[2]{'nextstate'})) { + $paramHash->{NEXTSTATE} = $token->[2]{'nextstate'}; + } + + # Populate the CHOICES element + my %choices; + + my %curr_groups = &Apache::longroup::coursegroups(); + foreach my $group_name (sort {lc($a) cmp lc($b)} (keys(%curr_groups))) { + push(@{$paramHash->{CHOICES}}, [$group_name, $group_name]); + } +} + +sub end_group { + my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; + + if ($target ne 'helper') { + return ''; + } + Apache::lonhelper::group->new(); +} +1; + package Apache::lonhelper::string; =pod @@ -2909,7 +3024,7 @@ sub postprocess { if (defined($self->{VALIDATOR})) { my $validator = eval($self->{VALIDATOR}); - die 'Died during evaluation of evaulation code; Perl said: ' . $@ if $@; + die 'Died during evaluation of validator code; Perl said: ' . $@ if $@; my $invalid = &$validator($helper, $state, $self, $self->getValue()); if ($invalid) { $self->{ERROR_MSG} = $invalid; @@ -3197,8 +3312,11 @@ sub render { } my $previous = HTML::Entities::encode(&mt("<- Previous"), '<>&"'); my $next = HTML::Entities::encode(&mt("Next ->"), '<>&"'); + my $target = " target='loncapaclient'"; + if (($env{'browser.interface'} eq 'textual') || + ($env{'environment.remote'} eq 'off')) { $target=''; } $result .= "<center>\n" . - "<form action='".$actionURL."' method='post' target='loncapaclient'>\n" . + "<form action='".$actionURL."' method='post' $target>\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" . @@ -3285,8 +3403,10 @@ sub render { if ($vars->{GRANULARITY} eq 'whole_course') { $resourceString .= '<li>'.&mt('for <b>all resources in the course</b>').'</li>'; if ($vars->{TARGETS} eq 'course') { - $level = 11; # general course, see lonparmset.pm perldoc + $level = 14; # general course, see lonparmset.pm perldoc } elsif ($vars->{TARGETS} eq 'section') { + $level = 9; + } elsif ($vars->{TARGETS} eq 'group') { $level = 6; } else { $level = 3; @@ -3301,8 +3421,10 @@ sub render { $symb = $res->symb(); $resourceString .= '<li>'.&mt('for the map named [_1]',"<b>$title</b>").'</li>'; if ($vars->{TARGETS} eq 'course') { - $level = 10; # general course, see lonparmset.pm perldoc + $level = 13; # general course, see lonparmset.pm perldoc } elsif ($vars->{TARGETS} eq 'section') { + $level = 8; + } elsif ($vars->{TARGETS} eq 'group') { $level = 5; } else { $level = 2; @@ -3318,8 +3440,10 @@ sub render { my $title = $res->compTitle(); $resourceString .= '<li>'.&mt('for the resource named [_1] part [_2]',"<b>$title</b>","<b>$part</b>").'</li>'; if ($vars->{TARGETS} eq 'course') { - $level = 7; # general course, see lonparmset.pm perldoc + $level = 10; # general course, see lonparmset.pm perldoc } elsif ($vars->{TARGETS} eq 'section') { + $level = 7; + } elsif ($vars->{TARGETS} eq 'group') { $level = 4; } else { $level = 1; @@ -3336,6 +3460,9 @@ sub render { if ($vars->{GRANULARITY} eq 'resource') { $result .= "<input type='hidden' name='symb' value='". HTML::Entities::encode($symb,"'<>&\"") . "' />\n"; + } elsif ($vars->{GRANULARITY} eq 'map') { + $result .= "<input type='hidden' name='pschp' value='". + $affectedResourceId."' />\n"; } my $part = $vars->{RESOURCE_ID_part}; if ($part eq 'All Parts' || !$part) { $part=0; } @@ -3396,15 +3523,17 @@ sub render { $result .= '<li>'.&mt('for section [_1]',"<b>$section</b>").'</li>'; $result .= "<input type='hidden' name='csec' value='" . HTML::Entities::encode($section,"'<>&\"") . "' />\n"; + } elsif ($vars->{TARGETS} eq 'group') { + my $group = $vars->{GROUP_NAME}; + $result .= '<li>'.&mt('for group [_1]',"<b>$group</b>").'</li>'; + $result .= "<input type='hidden' name='cgroup' value='" . + HTML::Entities::encode($group,"'<>&\"") . "' />\n"; } else { # FIXME: This is probably wasteful! Store the name! my $classlist = Apache::loncoursedata::get_classlist(); - my $username = $vars->{USER_NAME}; - # Chop off everything after the last colon (section) - my ($uname,$udom)=split(':',$username); + my ($uname,$udom)=split(':',$vars->{USER_NAME}); my $name = $classlist->{$uname.':'.$udom}->[6]; $result .= '<li>'.&mt('for [_1]',"<b>$name</b>").'</li>'; - my ($uname, $udom) = split /:/, $vars->{USER_NAME}; $result .= "<input type='hidden' name='uname' value='". HTML::Entities::encode($uname,"'<>&\"") . "' />\n"; $result .= "<input type='hidden' name='udom' value='". @@ -3422,7 +3551,6 @@ sub render { # Make the table appear $result .= "\n<input type='hidden' value='true' name='prevvisit' />"; - $result .= "\n<input type='hidden' value='all' name='pschp' />"; $result .= "\n<input type='hidden' value='$symb' name='pssymb' />"; $result .= "\n<input type='hidden' value='$paramlevel' name='parmlev' />";