--- loncom/interface/lonhelper.pm 2003/05/29 17:39:40 1.35 +++ loncom/interface/lonhelper.pm 2003/08/07 17:26:44 1.41 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # .helper XML handler to implement the LON-CAPA helper # -# $Id: lonhelper.pm,v 1.35 2003/05/29 17:39:40 bowersj2 Exp $ +# $Id: lonhelper.pm,v 1.41 2003/08/07 17:26:44 bowersj2 Exp $ # # Copyright Michigan State University Board of Trustees # @@ -779,6 +779,18 @@ some setting accidentally. Again, see the course initialization helper for examples. +B + +Some elements that accepts user input can contain a "validator" tag that, +when surrounded by "sub { my $helper = shift; my $state = shift; my $element = shift; my $val = shift " +and "}", where "$val" is the value the user entered, will form a subroutine +that when called will verify whether the given input is valid or not. If it +is valid, the routine will return a false value. If invalid, the routine +will return an error message to be displayed for the user. + +Consult the documentation for each element to see whether it supports this +tag. + B If the element stores the name of the variable in a 'variable' member, which @@ -790,7 +802,7 @@ this method. BEGIN { &Apache::lonhelper::register('Apache::lonhelper::element', ('nextstate', 'finalcode', - 'defaultvalue')); + 'defaultvalue', 'validator')); } # Because we use the param hash, this is often a sufficent @@ -855,6 +867,22 @@ sub start_defaultvalue { sub end_defaultvalue { return ''; } +sub start_validator { + my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; + + if ($target ne 'helper') { + return ''; + } + + $paramHash->{VALIDATOR} = &Apache::lonxml::get_all_text('/validator', + $parser); + $paramHash->{VALIDATOR} = 'sub { my $helper = shift; my $state = shift; my $element = shift; my $val = shift;' . + $paramHash->{VALIDATOR} . '}'; + return ''; +} + +sub end_validator { return ''; } + sub preprocess { return 1; } @@ -1694,6 +1722,10 @@ BUTTONS $col .= "checked "; $checked = 1; } + if ($multichoice) { # all resources start checked; see bug 1174 + $col .= "checked "; + $checked = 1; + } $col .= "value='" . HTML::Entities::encode(&$valueFunc($resource)) . "' />"; @@ -1743,9 +1775,10 @@ package Apache::lonhelper::student; Student elements display a choice of students enrolled in the current course. Currently it is primitive; this is expected to evolve later. -Student elements take two attributes: "variable", which means what -it usually does, and "multichoice", which if true allows the user -to select multiple students. +Student elements take three attributes: "variable", which means what +it usually does, "multichoice", which if true allows the user +to select multiple students, and "coursepersonnel" which if true +adds the course personnel to the top of the student selection. =cut @@ -1775,6 +1808,7 @@ sub start_student { $paramHash->{'variable'} = $token->[2]{'variable'}; $helper->declareVar($paramHash->{'variable'}); $paramHash->{'multichoice'} = $token->[2]{'multichoice'}; + $paramHash->{'coursepersonnel'} = $token->[2]{'coursepersonnel'}; if (defined($token->[2]{'nextstate'})) { $paramHash->{NEXTSTATE} = $token->[2]{'nextstate'}; } @@ -1821,30 +1855,60 @@ BUTTONS $result .= '' . $self->{ERROR_MSG} . '

'; } - # Load up the students - my $choices = &Apache::loncoursedata::get_classlist(); - my @keys = keys %{$choices}; + my $choices = []; + + # 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], '', $_]; + } + } + } + } # Constants my $section = Apache::loncoursedata::CL_SECTION(); my $fullname = Apache::loncoursedata::CL_FULLNAME(); + # Load up the students + my $classlist = &Apache::loncoursedata::get_classlist(); + my @keys = keys %{$classlist}; # Sort by: Section, name @keys = sort { - if ($choices->{$a}->[$section] ne $choices->{$b}->[$section]) { - return $choices->{$a}->[$section] cmp $choices->{$b}->[$section]; + if ($classlist->{$a}->[$section] ne $classlist->{$b}->[$section]) { + return $classlist->{$a}->[$section] cmp $classlist->{$b}->[$section]; } - return $choices->{$a}->[$fullname] cmp $choices->{$b}->[$fullname]; + return $classlist->{$a}->[$fullname] cmp $classlist->{$b}->[$fullname]; } @keys; + # username, fullname, section, type + for (@keys) { + push @$choices, [$_, $classlist->{$_}->[$fullname], + $classlist->{$_}->[$section], 'Student']; + } + + my $name = $self->{'coursepersonnel'} ? 'Name' : 'Student Name'; my $type = 'radio'; if ($self->{'multichoice'}) { $type = 'checkbox'; } $result .= "\n"; - $result .= "". - ""; + $result .= "". + "" . + ""; my $checked = 0; - foreach (@keys) { + for my $choice (@$choices) { $result .= "\n"; + . HTML::Entities::encode($choice->[2]) + . "\n\n"; } $result .= "
Student NameSection
$nameSectionRole
{$_}->[$section]) + " value='" . HTML::Entities::encode($choice->[0] . ':' . $choice->[2]) . "' />" - . HTML::Entities::encode($choices->{$_}->[$fullname]) + . HTML::Entities::encode($choice->[1]) . "" - . HTML::Entities::encode($choices->{$_}->[$section]) - . "
" + . HTML::Entities::encode($choice->[3]) . "
\n\n"; @@ -2262,6 +2327,8 @@ also pass through 'maxlength' and 'size' string honors the defaultvalue tag, if given. +string honors the validation function, if given. + =cut no strict; @@ -2307,7 +2374,13 @@ sub end_string { sub render { my $self = shift; - my $result = '{ERROR_MSG}) { + $result .= '
' . $self->{ERROR_MSG} . '

'; + } + + $result .= '{'size'})) { $result .= ' size="' . $self->{'size'} . '"'; @@ -2331,8 +2404,19 @@ sub render { # If a NEXTSTATE was given, switch to it sub postprocess { my $self = shift; - if (defined($self->{NEXTSTATE})) { - $helper->changeState($self->{NEXTSTATE}); + + if (defined($self->{VALIDATOR})) { + my $validator = eval($self->{VALIDATOR}); + die 'Died during evaluation of evaulation 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'}); } return 1; @@ -2570,31 +2654,33 @@ sub render { } } - if (scalar(@results) == 0) { - return ''; - } - - my $result = "'; + return $result; } sub overrideForm { @@ -2646,10 +2732,13 @@ sub render { # FIXME: Unify my designators with the standard ones my %dateTypeHash = ('open_date' => "Opening Date", 'due_date' => "Due Date", - 'answer_date' => "Answer Date"); + 'answer_date' => "Answer Date", + 'tries' => 'Number of Tries' + ); my %parmTypeHash = ('open_date' => "0_opendate", 'due_date' => "0_duedate", - 'answer_date' => "0_answerdate"); + 'answer_date' => "0_answerdate", + 'tries' => '0_maxtries' ); my $affectedResourceId = ""; my $parm_name = $parmTypeHash{$vars->{ACTION_TYPE}}; @@ -2666,9 +2755,7 @@ sub render { $symb = 'a'; $paramlevel = 'general'; } elsif ($vars->{GRANULARITY} eq 'map') { - my $navmap = Apache::lonnavmaps::navmap->new( - $ENV{"request.course.fn"}.".db", - $ENV{"request.course.fn"}."_parms.db", 0, 0); + my $navmap = Apache::lonnavmaps::navmap->new(); my $res = $navmap->getByMapPc($vars->{RESOURCE_ID}); my $title = $res->compTitle(); $symb = $res->symb(); @@ -2678,9 +2765,7 @@ sub render { $affectedResourceId = $vars->{RESOURCE_ID}; $paramlevel = 'map'; } else { - my $navmap = Apache::lonnavmaps::navmap->new( - $ENV{"request.course.fn"}.".db", - $ENV{"request.course.fn"}."_parms.db", 0, 0); + my $navmap = Apache::lonnavmaps::navmap->new(); my $res = $navmap->getById($vars->{RESOURCE_ID}); $symb = $res->symb(); my $title = $res->compTitle(); @@ -2695,8 +2780,11 @@ sub render { $result .= '

Confirm that this information is correct, then click "Finish Wizard" to complete setting the parameter.