Diff for /loncom/interface/lonhelper.pm between versions 1.26 and 1.43

version 1.26, 2003/05/08 20:10:49 version 1.43, 2003/08/13 14:52:08
Line 53  Each state contains one or more state el Line 53  Each state contains one or more state el
 messages, resource selections, or date queries.  messages, resource selections, or date queries.
   
 The helper tag is required to have one attribute, "title", which is the name  The helper tag is required to have one attribute, "title", which is the name
 of the helper itself, such as "Parameter helper".   of the helper itself, such as "Parameter helper". The helper tag may optionally
   have a "requiredpriv" attribute, specifying the priviledge a user must have
   to use the helper, or get denied access. See loncom/auth/rolesplain.tab for
   useful privs. Default is full access, which is often wrong!
   
 =head2 State tags  =head2 State tags
   
Line 234  sub real_handler { Line 237  sub real_handler {
     my $file;      my $file;
     read $fh, $file, 100000000;      read $fh, $file, 100000000;
   
   
     # Send header, don't cache this page      # Send header, don't cache this page
     if ($r->header_only) {      if ($r->header_only) {
         if ($ENV{'browser.mathml'}) {          if ($ENV{'browser.mathml'}) {
Line 256  sub real_handler { Line 260  sub real_handler {
     # xml parsing      # xml parsing
     &Apache::lonxml::xmlparse($r, 'helper', $file);      &Apache::lonxml::xmlparse($r, 'helper', $file);
   
       my $allowed = $helper->allowedCheck();
       if (!$allowed) {
           $ENV{'user.error.msg'} = $ENV{'request.uri'}.':'.$helper->{REQUIRED_PRIV}.
               ":0:0:Permission denied to access this helper.";
           return HTTP_NOT_ACCEPTABLE;
       }
   
     $helper->process();      $helper->process();
   
     $r->print($helper->display());      $r->print($helper->display());
    return OK;      return OK;
 }  }
   
 sub registerHelperTags {  sub registerHelperTags {
Line 283  sub start_helper { Line 294  sub start_helper {
   
     registerHelperTags();      registerHelperTags();
   
     Apache::lonhelper::helper->new($token->[2]{'title'});      Apache::lonhelper::helper->new($token->[2]{'title'}, $token->[2]{'requiredpriv'});
     return '';      return '';
 }  }
   
Line 342  sub new { Line 353  sub new {
     my $self = {};      my $self = {};
   
     $self->{TITLE} = shift;      $self->{TITLE} = shift;
       $self->{REQUIRED_PRIV} = shift;
           
     Apache::loncommon::get_unprocessed_cgi($ENV{QUERY_STRING});  
   
     # If there is a state from the previous form, use that. If there is no      # If there is a state from the previous form, use that. If there is no
     # state, use the start state parameter.      # state, use the start state parameter.
     if (defined $ENV{"form.CURRENT_STATE"})      if (defined $ENV{"form.CURRENT_STATE"})
Line 460  sub declareVar { Line 470  sub declareVar {
   
     my $envname = 'form.' . $var . '.forminput';      my $envname = 'form.' . $var . '.forminput';
     if (defined($ENV{$envname})) {      if (defined($ENV{$envname})) {
         $self->{VARS}->{$var} = $ENV{$envname};          if (ref($ENV{$envname})) {
               $self->{VARS}->{$var} = join('|||', @{$ENV{$envname}});
           } else {
               $self->{VARS}->{$var} = $ENV{$envname};
           }
     }      }
 }  }
   
   sub allowedCheck {
       my $self = shift;
   
       if (!defined($self->{REQUIRED_PRIV})) { 
           return 1;
       }
   
       return Apache::lonnet::allowed($self->{REQUIRED_PRIV}, $ENV{'request.course.id'});
   }
   
 sub changeState {  sub changeState {
     my $self = shift;      my $self = shift;
     $self->{STATE} = shift;      $self->{STATE} = shift;
Line 544  sub display { Line 568  sub display {
     </head>      </head>
     $bodytag      $bodytag
 HEADER  HEADER
     if (!$state->overrideForm()) { $result.="<form name='helpform' method='GET'>"; }      if (!$state->overrideForm()) { $result.="<form name='helpform' method='POST'>"; }
     $result .= <<HEADER;      $result .= <<HEADER;
         <table border="0"><tr><td>          <table border="0" width='100%'><tr><td>
         <h2><i>$stateTitle</i></h2>          <h2><i>$stateTitle</i></h2>
 HEADER  HEADER
   
       $result .= "<table cellpadding='10' width='100%'><tr><td rowspan='2' valign='top'>";
   
     if (!$state->overrideForm()) {      if (!$state->overrideForm()) {
         $result .= $self->_saveVars();          $result .= $self->_saveVars();
     }      }
     $result .= $state->render() . "<p>&nbsp;</p>";      $result .= $state->render();
   
       $result .= "</td><td valign='top' align='right'>";
   
       # Warning: Copy and pasted from below, because it's too much trouble to 
       # turn this into a subroutine
       if (!$state->overrideForm()) {
           if ($self->{STATE} ne $self->{START_STATE}) {
               #$result .= '<input name="SUBMIT" type="submit" value="&lt;- Previous" />&nbsp;&nbsp;';
           }
           if ($self->{DONE}) {
               my $returnPage = $self->{RETURN_PAGE};
               $result .= "<a href=\"$returnPage\">End Helper</a>";
           }
           else {
               $result .= '<nobr><input name="back" type="button" ';
               $result .= 'value="&lt;- Previous" onclick="history.go(-1)" /> ';
               $result .= '<input name="SUBMIT" type="submit" value="Next -&gt;" /></nobr>';
           }
       }
   
       $result .= "</td></tr><tr><td valign='bottom' align='right'>";
   
       # Warning: Copy and pasted from above, because it's too much trouble to 
       # turn this into a subroutine
     if (!$state->overrideForm()) {      if (!$state->overrideForm()) {
         $result .= '<center>';  
         if ($self->{STATE} ne $self->{START_STATE}) {          if ($self->{STATE} ne $self->{START_STATE}) {
             #$result .= '<input name="SUBMIT" type="submit" value="&lt;- Previous" />&nbsp;&nbsp;';              #$result .= '<input name="SUBMIT" type="submit" value="&lt;- Previous" />&nbsp;&nbsp;';
         }          }
Line 565  HEADER Line 613  HEADER
             $result .= "<a href=\"$returnPage\">End Helper</a>";              $result .= "<a href=\"$returnPage\">End Helper</a>";
         }          }
         else {          else {
             $result .= '<input name="back" type="button" ';              $result .= '<nobr><input name="back" type="button" ';
             $result .= 'value="&lt;- Previous" onclick="history.go(-1)" /> ';              $result .= 'value="&lt;- Previous" onclick="history.go(-1)" /> ';
             $result .= '<input name="SUBMIT" type="submit" value="Next -&gt;" />';              $result .= '<input name="SUBMIT" type="submit" value="Next -&gt;" /></nobr>';
         }          }
         $result .= "</center>\n";  
     }      }
   
     #foreach my $key (keys %{$self->{VARS}}) {      #foreach my $key (keys %{$self->{VARS}}) {
     #    $result .= "|$key| -> " . $self->{VARS}->{$key} . "<br />";      #    $result .= "|$key| -> " . $self->{VARS}->{$key} . "<br />";
     #}      #}
   
       $result .= "</td></tr></table>";
   
     $result .= <<FOOTER;      $result .= <<FOOTER;
               </td>                </td>
             </tr>              </tr>
Line 688  sub render { Line 737  sub render {
     for my $element (@{$self->{ELEMENTS}}) {      for my $element (@{$self->{ELEMENTS}}) {
         push @results, $element->render();          push @results, $element->render();
     }      }
   
     return join("\n", @results);      return join("\n", @results);
 }  }
   
Line 700  package Apache::lonhelper::element; Line 750  package Apache::lonhelper::element;
   
 =head2 Element Base Class  =head2 Element Base Class
   
 The Apache::lonhelper::element base class provides support methods for  The Apache::lonhelper::element base class provides support for elements
 the elements to use, such as a multiple value processer.  and defines some generally useful tags for use in elements.
   
 B<Methods>:  
   
 =over 4  
   
 =item * process_multiple_choices(formName, varName): Process the form   
 element named "formName" and place the selected items into the helper   
 variable named varName. This is for things like checkboxes or   
 multiple-selection listboxes where the user can select more then   
 one entry. The selected entries are delimited by triple pipes in   
 the helper variables, like this:    
   
  CHOICE_1|||CHOICE_2|||CHOICE_3  
   
 =back  
   
 B<finalcode tag>  B<finalcode tag>
   
Line 744  some setting accidentally. Line 779  some setting accidentally.
   
 Again, see the course initialization helper for examples.  Again, see the course initialization helper for examples.
   
   B<validator tag>
   
   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<getValue method>
   
   If the element stores the name of the variable in a 'variable' member, which
   the provided ones all do, you can retreive the value of the variable by calling
   this method.
   
 =cut  =cut
   
 BEGIN {  BEGIN {
     &Apache::lonhelper::register('Apache::lonhelper::element',      &Apache::lonhelper::register('Apache::lonhelper::element',
                                  ('nextstate', 'finalcode',                                   ('nextstate', 'finalcode',
                                   'defaultvalue'));                                    'defaultvalue', 'validator'));
 }  }
   
 # Because we use the param hash, this is often a sufficent  # Because we use the param hash, this is often a sufficent
Line 814  sub start_defaultvalue { Line 867  sub start_defaultvalue {
   
 sub end_defaultvalue { return ''; }  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 {  sub preprocess {
     return 1;      return 1;
 }  }
Line 830  sub overrideForm { Line 899  sub overrideForm {
     return 0;      return 0;
 }  }
   
 sub process_multiple_choices {  sub getValue {
     my $self = shift;      my $self = shift;
     my $formname = shift;      return $helper->{VARS}->{$self->{'variable'}};
     my $var = shift;  
   
     # Must extract values from data directly, as there  
     # may be more then one.  
     my @values;  
     for my $formparam (split (/&/, $ENV{QUERY_STRING})) {  
         my ($name, $value) = split(/=/, $formparam);  
         if ($name ne $formname) {  
             next;  
         }  
         $value =~ tr/+/ /;  
         $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;  
         push @values, $value;  
     }  
     $helper->{VARS}->{$var} = join('|||', @values);  
       
     return;  
 }  }
   
 1;  1;
Line 1090  sub end_choice { Line 1142  sub end_choice {
 }  }
   
 sub render {  sub render {
     # START HERE: Replace this with correct choices code.  
     my $self = shift;      my $self = shift;
     my $var = $self->{'variable'};      my $var = $self->{'variable'};
     my $buttons = '';      my $buttons = '';
Line 1136  BUTTONS Line 1187  BUTTONS
     if (defined($self->{DEFAULT_VALUE})) {      if (defined($self->{DEFAULT_VALUE})) {
         $checkedChoicesFunc = eval ($self->{DEFAULT_VALUE});          $checkedChoicesFunc = eval ($self->{DEFAULT_VALUE});
         die 'Error in default value code for variable ' .           die 'Error in default value code for variable ' . 
             {'variable'} . ', Perl said:' . $@ if $@;              $self->{'variable'} . ', Perl said: ' . $@ if $@;
     } else {      } else {
         $checkedChoicesFunc = sub { return ''; };          $checkedChoicesFunc = sub { return ''; };
     }      }
Line 1204  sub postprocess { Line 1255  sub postprocess {
         return 0;          return 0;
     }      }
   
     if ($self->{'multichoice'}) {      if (ref($chosenValue)) {
         $self->process_multiple_choices($self->{'variable'}.'.forminput',          $helper->{VARS}->{$self->{'variable'}} = join('|||', @$chosenValue);
                                         $self->{'variable'});      }
   
       if (defined($self->{NEXTSTATE})) {
           $helper->changeState($self->{NEXTSTATE});
       }
       
       foreach my $choice (@{$self->{CHOICES}}) {
           if ($choice->[1] eq $chosenValue) {
               if (defined($choice->[2])) {
                   $helper->changeState($choice->[2]);
               }
           }
       }
       return 1;
   }
   1;
   
   package Apache::lonhelper::dropdown;
   
   =pod
   
   =head2 Element: dropdown
   
   A drop-down provides a drop-down box instead of a radio button
   box. Because most people do not know how to use a multi-select
   drop-down box, that option is not allowed. Otherwise, the arguments
   are the same as "choices", except "allowempty" is also meaningless.
   
   <dropdown> takes an attribute "variable" to control which helper variable
   the result is stored in.
   
   B<SUB-TAGS>
   
   <choice>, which acts just as it does in the "choices" element.
   
   =back
   
   =cut
   
   no strict;
   @ISA = ("Apache::lonhelper::element");
   use strict;
   
   BEGIN {
       &Apache::lonhelper::register('Apache::lonhelper::dropdown',
                                 ('dropdown'));
   }
   
   sub new {
       my $ref = Apache::lonhelper::element->new();
       bless($ref);
   }
   
   # CONSTRUCTION: Construct the message element from the XML
   sub start_dropdown {
       my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
   
       if ($target ne 'helper') {
           return '';
       }
   
       # Need to initialize the choices list, so everything can assume it exists
       $paramHash->{'variable'} = $token->[2]{'variable'} if (!defined($paramHash->{'variable'}));
       $helper->declareVar($paramHash->{'variable'});
       $paramHash->{CHOICES} = [];
       return '';
   }
   
   sub end_dropdown {
       my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
   
       if ($target ne 'helper') {
           return '';
       }
       Apache::lonhelper::dropdown->new();
       return '';
   }
   
   sub render {
       my $self = shift;
       my $var = $self->{'variable'};
       my $result = '';
   
       if (defined $self->{ERROR_MSG}) {
           $result .= '<br /><font color="#FF0000">' . $self->{ERROR_MSG} . '</font><br />';
       }
   
       my %checkedChoices;
       my $checkedChoicesFunc;
   
       if (defined($self->{DEFAULT_VALUE})) {
           $checkedChoicesFunc = eval ($self->{DEFAULT_VALUE});
           die 'Error in default value code for variable ' . 
               $self->{'variable'} . ', Perl said: ' . $@ if $@;
       } else {
           $checkedChoicesFunc = sub { return ''; };
       }
   
       # single choice
       my $selectedChoice = &$checkedChoicesFunc($helper, $self);
       
       my $foundChoice = 0;
       
       # check that the choice is in the list of choices.
       for my $choice (@{$self->{CHOICES}}) {
    if ($choice->[1] eq $selectedChoice) {
       $checkedChoices{$choice->[1]} = 1;
       $foundChoice = 1;
    }
       }
       
       # If we couldn't find the choice, pick the first one 
       if (!$foundChoice) {
    $checkedChoices{$self->{CHOICES}->[0]->[1]} = 1;
       }
   
       $result .= "<select name='${var}.forminput'>\n";
       foreach my $choice (@{$self->{CHOICES}}) {
           $result .= "<option value='" . 
               HTML::Entities::encode($choice->[1]) 
               . "'";
           if ($checkedChoices{$choice->[1]}) {
               $result .= " selected";
           }
           my $choiceLabel = $choice->[0];
           if ($choice->[4]) {  # if we need to evaluate this choice
               $choiceLabel = "sub { my $helper = shift; my $state = shift;" .
                   $choiceLabel . "}";
               $choiceLabel = eval($choiceLabel);
               $choiceLabel = &$choiceLabel($helper, $self);
           }
           $result .= ">" . $choiceLabel . "\n";
       }
       $result .= "</select>\n";
   
       return $result;
   }
   
   # If a NEXTSTATE was given or a nextstate for this choice was
   # given, switch to it
   sub postprocess {
       my $self = shift;
       my $chosenValue = $ENV{'form.' . $self->{'variable'} . '.forminput'};
   
       if (!defined($chosenValue) && !$self->{'allowempty'}) {
           $self->{ERROR_MSG} = "You must choose one or more choices to" .
               " continue.";
           return 0;
     }      }
   
     if (defined($self->{NEXTSTATE})) {      if (defined($self->{NEXTSTATE})) {
Line 1452  variable stores the results. It also tak Line 1650  variable stores the results. It also tak
 which controls whether the user can select more then one resource. The   which controls whether the user can select more then one resource. The 
 "toponly" attribute controls whether the resource display shows just the  "toponly" attribute controls whether the resource display shows just the
 resources in that sequence, or recurses into all sub-sequences, defaulting  resources in that sequence, or recurses into all sub-sequences, defaulting
 to false.  to false. The "suppressEmptySequences" attribute reflects the 
   suppressEmptySequences argument to the render routine, which will cause
   folders that have all of their contained resources filtered out to also
   be filtered out.
   
 B<SUB-TAGS>  B<SUB-TAGS>
   
Line 1513  sub start_resource { Line 1714  sub start_resource {
     $paramHash->{'variable'} = $token->[2]{'variable'};      $paramHash->{'variable'} = $token->[2]{'variable'};
     $helper->declareVar($paramHash->{'variable'});      $helper->declareVar($paramHash->{'variable'});
     $paramHash->{'multichoice'} = $token->[2]{'multichoice'};      $paramHash->{'multichoice'} = $token->[2]{'multichoice'};
       $paramHash->{'suppressEmptySequences'} = $token->[2]{'suppressEmptySequences'};
     $paramHash->{'toponly'} = $token->[2]{'toponly'};      $paramHash->{'toponly'} = $token->[2]{'toponly'};
     return '';      return '';
 }  }
Line 1667  BUTTONS Line 1869  BUTTONS
                 $col .= "checked ";                  $col .= "checked ";
                 $checked = 1;                  $checked = 1;
             }              }
       if ($multichoice) { # all resources start checked; see bug 1174
    $col .= "checked ";
    $checked = 1;
       }
             $col .= "value='" .               $col .= "value='" . 
                 HTML::Entities::encode(&$valueFunc($resource))                   HTML::Entities::encode(&$valueFunc($resource)) 
                 . "' /></td>";                  . "' /></td>";
Line 1681  BUTTONS Line 1887  BUTTONS
                                        'showParts' => 0,                                         'showParts' => 0,
                                        'filterFunc' => $filterFunc,                                         'filterFunc' => $filterFunc,
                                        'resource_no_folder_link' => 1,                                         'resource_no_folder_link' => 1,
                                          'suppressEmptySequences' => $self->{'suppressEmptySequences'},
                                        'iterator_map' => $mapUrl }                                         'iterator_map' => $mapUrl }
                                        );                                         );
   
Line 1692  BUTTONS Line 1899  BUTTONS
 sub postprocess {  sub postprocess {
     my $self = shift;      my $self = shift;
   
     if ($self->{'multichoice'}) {  
         $self->process_multiple_choices($self->{'variable'}.'.forminput',  
                                         $self->{'variable'});  
     }  
   
     if ($self->{'multichoice'} && !$helper->{VARS}->{$self->{'variable'}}) {      if ($self->{'multichoice'} && !$helper->{VARS}->{$self->{'variable'}}) {
         $self->{ERROR_MSG} = 'You must choose at least one resource to continue.';          $self->{ERROR_MSG} = 'You must choose at least one resource to continue.';
         return 0;          return 0;
Line 1720  package Apache::lonhelper::student; Line 1922  package Apache::lonhelper::student;
 Student elements display a choice of students enrolled in the current  Student elements display a choice of students enrolled in the current
 course. Currently it is primitive; this is expected to evolve later.  course. Currently it is primitive; this is expected to evolve later.
   
 Student elements take two attributes: "variable", which means what  Student elements take three attributes: "variable", which means what
 it usually does, and "multichoice", which if true allows the user  it usually does, "multichoice", which if true allows the user
 to select multiple students.  to select multiple students, and "coursepersonnel" which if true 
   adds the course personnel to the top of the student selection.
   
 =cut  =cut
   
Line 1752  sub start_student { Line 1955  sub start_student {
     $paramHash->{'variable'} = $token->[2]{'variable'};      $paramHash->{'variable'} = $token->[2]{'variable'};
     $helper->declareVar($paramHash->{'variable'});      $helper->declareVar($paramHash->{'variable'});
     $paramHash->{'multichoice'} = $token->[2]{'multichoice'};      $paramHash->{'multichoice'} = $token->[2]{'multichoice'};
       $paramHash->{'coursepersonnel'} = $token->[2]{'coursepersonnel'};
     if (defined($token->[2]{'nextstate'})) {      if (defined($token->[2]{'nextstate'})) {
         $paramHash->{NEXTSTATE} = $token->[2]{'nextstate'};          $paramHash->{NEXTSTATE} = $token->[2]{'nextstate'};
     }      }
Line 1798  BUTTONS Line 2002  BUTTONS
         $result .= '<font color="#FF0000">' . $self->{ERROR_MSG} . '</font><br /><br />';          $result .= '<font color="#FF0000">' . $self->{ERROR_MSG} . '</font><br /><br />';
     }      }
   
     # Load up the students      my $choices = [];
     my $choices = &Apache::loncoursedata::get_classlist();  
     my @keys = keys %{$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      # Constants
     my $section = Apache::loncoursedata::CL_SECTION();      my $section = Apache::loncoursedata::CL_SECTION();
     my $fullname = Apache::loncoursedata::CL_FULLNAME();      my $fullname = Apache::loncoursedata::CL_FULLNAME();
   
       # Load up the students
       my $classlist = &Apache::loncoursedata::get_classlist();
       my @keys = keys %{$classlist};
     # Sort by: Section, name      # Sort by: Section, name
     @keys = sort {      @keys = sort {
         if ($choices->{$a}->[$section] ne $choices->{$b}->[$section]) {          if ($classlist->{$a}->[$section] ne $classlist->{$b}->[$section]) {
             return $choices->{$a}->[$section] cmp $choices->{$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;      } @keys;
   
       # username, fullname, section, type
       for (@keys) {
    push @$choices, [$_, $classlist->{$_}->[$fullname], 
    $classlist->{$_}->[$section], 'Student'];
       }
   
       my $name = $self->{'coursepersonnel'} ? 'Name' : 'Student Name';
     my $type = 'radio';      my $type = 'radio';
     if ($self->{'multichoice'}) { $type = 'checkbox'; }      if ($self->{'multichoice'}) { $type = 'checkbox'; }
     $result .= "<table cellspacing='2' cellpadding='2' border='0'>\n";      $result .= "<table cellspacing='2' cellpadding='2' border='0'>\n";
     $result .= "<tr><td></td><td align='center'><b>Student Name</b></td>".      $result .= "<tr><td></td><td align='center'><b>$name</b></td>".
         "<td align='center'><b>Section</b></td></tr>";          "<td align='center'><b>Section</b></td>" . 
    "<td align='center'><b>Role</b></td></tr>";
   
     my $checked = 0;      my $checked = 0;
     foreach (@keys) {      for my $choice (@$choices) {
         $result .= "<tr><td><input type='$type' name='" .          $result .= "<tr><td><input type='$type' name='" .
             $self->{'variable'} . '.forminput' . "'";              $self->{'variable'} . '.forminput' . "'";
                           
Line 1830  BUTTONS Line 2064  BUTTONS
             $checked = 1;              $checked = 1;
         }          }
         $result .=          $result .=
             " value='" . HTML::Entities::encode($_ . ':' . $choices->{$_}->[$section])              " value='" . HTML::Entities::encode($choice->[0] . ':' . $choice->[2])
             . "' /></td><td>"              . "' /></td><td>"
             . HTML::Entities::encode($choices->{$_}->[$fullname])              . HTML::Entities::encode($choice->[1])
             . "</td><td align='center'>"               . "</td><td align='center'>" 
             . HTML::Entities::encode($choices->{$_}->[$section])              . HTML::Entities::encode($choice->[2])
             . "</td></tr>\n";              . "</td>\n<td>" 
       . HTML::Entities::encode($choice->[3]) . "</td></tr>\n";
     }      }
   
     $result .= "</table>\n\n";      $result .= "</table>\n\n";
Line 1854  sub postprocess { Line 2089  sub postprocess {
         return 0;          return 0;
     }      }
   
     if ($self->{'multichoice'}) {  
         $self->process_multiple_choices($self->{'variable'}.'.forminput',  
                                         $self->{'variable'});  
     }  
     if (defined($self->{NEXTSTATE})) {      if (defined($self->{NEXTSTATE})) {
         $helper->changeState($self->{NEXTSTATE});          $helper->changeState($self->{NEXTSTATE});
     }      }
Line 1903  no strict; Line 2134  no strict;
 @ISA = ("Apache::lonhelper::element");  @ISA = ("Apache::lonhelper::element");
 use strict;  use strict;
   
   use Apache::lonpubdir; # for getTitleString
   
 BEGIN {  BEGIN {
     &Apache::lonhelper::register('Apache::lonhelper::files',      &Apache::lonhelper::register('Apache::lonhelper::files',
                                  ('files', 'filechoice', 'filefilter'));                                   ('files', 'filechoice', 'filefilter'));
Line 2059  BUTTONS Line 2292  BUTTONS
  $color = '';   $color = '';
     }      }
   
               # Get the title
               my $title = Apache::lonpubdir::getTitleString($fileName);
   
             # Netscape 4 is stupid and there's nowhere to put the              # Netscape 4 is stupid and there's nowhere to put the
             # information on the input tag that the file is Published,              # information on the input tag that the file is Published,
             # Unpublished, etc. In *real* browsers we can just say              # Unpublished, etc. In *real* browsers we can just say
Line 2085  BUTTONS Line 2321  BUTTONS
             if (!$self->{'multichoice'} && $choices == 0) {              if (!$self->{'multichoice'} && $choices == 0) {
                 $result .= ' checked';                  $result .= ' checked';
             }              }
             $result .= "/></td><td bgcolor='$color'>" . $file .              $result .= "/></td><td bgcolor='$color'>" . $file . "</td>" .
                  "</td><td bgcolor='$color'>$status</td></tr>\n";                  "<td bgcolor='$color'>$title</td>" .
                   "<td bgcolor='$color'>$status</td>" . "</tr>\n";
             $choices++;              $choices++;
         }          }
     }      }
Line 2142  sub postprocess { Line 2379  sub postprocess {
         return 0;          return 0;
     }      }
   
     if ($self->{'multichoice'}) {  
         $self->process_multiple_choices($self->{'variable'}.'.forminput',  
                                         $self->{'variable'});  
     }  
     if (defined($self->{NEXTSTATE})) {      if (defined($self->{NEXTSTATE})) {
         $helper->changeState($self->{NEXTSTATE});          $helper->changeState($self->{NEXTSTATE});
     }      }
Line 2229  sub end_section { Line 2462  sub end_section {
 }      }    
 1;  1;
   
   package Apache::lonhelper::string;
   
   =pod
   
   =head2 Element: string
   
   string elements provide a string entry field for the user. string elements
   take the usual 'variable' and 'nextstate' parameters. string elements
   also pass through 'maxlength' and 'size' attributes to the input tag.
   
   string honors the defaultvalue tag, if given.
   
   string honors the validation function, if given.
   
   =cut
   
   no strict;
   @ISA = ("Apache::lonhelper::element");
   use strict;
   
   BEGIN {
       &Apache::lonhelper::register('Apache::lonhelper::string',
                                 ('string'));
   }
   
   sub new {
       my $ref = Apache::lonhelper::element->new();
       bless($ref);
   }
   
   # CONSTRUCTION: Construct the message element from the XML
   sub start_string {
       my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
   
       if ($target ne 'helper') {
           return '';
       }
   
       $paramHash->{'variable'} = $token->[2]{'variable'};
       $helper->declareVar($paramHash->{'variable'});
       $paramHash->{'nextstate'} = $token->[2]{'nextstate'};
       $paramHash->{'maxlength'} = $token->[2]{'maxlength'};
       $paramHash->{'size'} = $token->[2]{'size'};
   
       return '';
   }
   
   sub end_string {
       my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
   
       if ($target ne 'helper') {
           return '';
       }
       Apache::lonhelper::string->new();
       return '';
   }
   
   sub render {
       my $self = shift;
       my $result = '';
   
       if (defined $self->{ERROR_MSG}) {
           $result .= '<br /><font color="#FF0000">' . $self->{ERROR_MSG} . '</font><br /><br />';
       }
   
       $result .= '<input type="string" name="' . $self->{'variable'} . '.forminput"';
   
       if (defined($self->{'size'})) {
           $result .= ' size="' . $self->{'size'} . '"';
       }
       if (defined($self->{'maxlength'})) {
           $result .= ' maxlength="' . $self->{'maxlength'} . '"';
       }
   
       if (defined($self->{DEFAULT_VALUE})) {
           my $valueFunc = eval($self->{DEFAULT_VALUE});
           die 'Error in default value code for variable ' . 
               $self->{'variable'} . ', Perl said: ' . $@ if $@;
           $result .= ' value="' . &$valueFunc($helper, $self) . '"';
       }
   
       $result .= ' />';
   
       return $result;
   }
   
   # If a NEXTSTATE was given, switch to it
   sub postprocess {
       my $self = shift;
   
       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;
   }
   
   1;
   
 package Apache::lonhelper::general;  package Apache::lonhelper::general;
   
 =pod  =pod
Line 2362  sub end_eval { Line 2704  sub end_eval {
   
 1;  1;
   
   package Apache::lonhelper::final;
   
   =pod
   
   =head2 Element: final
   
   <final> is a special element that works with helpers that use the <finalcode>
   tag. It goes through all the states and elements, executing the <finalcode>
   snippets and collecting the results. Finally, it takes the user out of the
   helper, going to a provided page.
   
   If the parameter "restartCourse" is true, this will override the buttons and
   will make a "Finish Helper" button that will re-initialize the course for them,
   which is useful for the Course Initialization helper so the users never see
   the old values taking effect.
   
   =cut
   
   no strict;
   @ISA = ("Apache::lonhelper::element");
   use strict;
   
   BEGIN {
       &Apache::lonhelper::register('Apache::lonhelper::final',
                                    ('final', 'exitpage'));
   }
   
   sub new {
       my $ref = Apache::lonhelper::element->new();
       bless($ref);
   }
   
   sub start_final { 
       my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
   
       if ($target ne 'helper') {
           return '';
       }
   
       $paramHash->{'restartCourse'} = $token->[2]{'restartCourse'};
   
       return ''; 
   }
   
   sub end_final {
       my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
   
       if ($target ne 'helper') {
           return '';
       }
   
       Apache::lonhelper::final->new();
      
       return '';
   }
   
   sub start_exitpage {
       my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
   
       if ($target ne 'helper') {
           return '';
       }
   
       $paramHash->{EXIT_PAGE} = &Apache::lonxml::get_all_text('/exitpage',
                                                               $parser);
   
       return '';
   }
   
   sub end_exitpage { return ''; }
   
   sub render {
       my $self = shift;
   
       my @results;
   
       # Collect all the results
       for my $stateName (keys %{$helper->{STATES}}) {
           my $state = $helper->{STATES}->{$stateName};
           
           for my $element (@{$state->{ELEMENTS}}) {
               if (defined($element->{FINAL_CODE})) {
                   # Compile the code.
                   my $code = 'sub { my $helper = shift; my $element = shift; ' 
                       . $element->{FINAL_CODE} . '}';
                   $code = eval($code);
                   die 'Error while executing final code for element with var ' .
                       $element->{'variable'} . ', Perl said: ' . $@ if $@;
   
                   my $result = &$code($helper, $element);
                   if ($result) {
                       push @results, $result;
                   }
               }
           }
       }
   
       my $result;
   
       if (scalar(@results) != 0) {
    $result .= "<ul>\n";
    for my $re (@results) {
       $result .= '    <li>' . $re . "</li>\n";
    }
   
    if (!@results) {
       $result .= '    <li>No changes were made to current settings.</li>';
    }
   
    $result .= '</ul>';
       }
   
       if ($self->{'restartCourse'}) {
           $result .= "<center>\n" .
               "<form action='/adm/roles' method='post' target='loncapaclient'>\n" .
               "<input type='button' onclick='history.go(-1)' value='&lt;- Previous' />" .
               "<input type='hidden' name='orgurl' value='/adm/menu' />" .
               "<input type='hidden' name='selectrole' value='1' />\n" .
               "<input type='hidden' name='" . $ENV{'request.role'} . 
               "' value='1' />\n<input type='submit' value='Finish Course Initialization' />\n" .
               "</form></center>";
       }
   
       return $result;
   }
   
   sub overrideForm {
       my $self = shift;
       return $self->{'restartCourse'};
   }
   
   1;
   
 package Apache::lonhelper::parmwizfinal;  package Apache::lonhelper::parmwizfinal;
   
 # This is the final state for the parmwizard. It is not generally useful,  # This is the final state for the parmwizard. It is not generally useful,
Line 2404  sub render { Line 2879  sub render {
     # FIXME: Unify my designators with the standard ones      # FIXME: Unify my designators with the standard ones
     my %dateTypeHash = ('open_date' => "Opening Date",      my %dateTypeHash = ('open_date' => "Opening Date",
                         'due_date' => "Due Date",                          'due_date' => "Due Date",
                         'answer_date' => "Answer Date");                          'answer_date' => "Answer Date",
    'tries' => 'Number of Tries'
    );
     my %parmTypeHash = ('open_date' => "0_opendate",      my %parmTypeHash = ('open_date' => "0_opendate",
                         'due_date' => "0_duedate",                          'due_date' => "0_duedate",
                         'answer_date' => "0_answerdate");                          'answer_date' => "0_answerdate",
    'tries' => '0_maxtries' );
           
     my $result = "<form name='helpform' method='get' action='/adm/parmset'>\n";  
     $result .= '<p>Confirm that this information is correct, then click &quot;Finish Wizard&quot; to complete setting the parameter.<ul>';  
     my $affectedResourceId = "";      my $affectedResourceId = "";
     my $parm_name = $parmTypeHash{$vars->{ACTION_TYPE}};      my $parm_name = $parmTypeHash{$vars->{ACTION_TYPE}};
     my $level = "";      my $level = "";
       my $resourceString;
       my $symb;
       my $paramlevel;
   
       # Print the granularity, depending on the action
       if ($vars->{GRANULARITY} eq 'whole_course') {
           $resourceString .= '<li>for <b>all resources in the course</b></li>';
           $level = 9; # general course, see lonparmset.pm perldoc
           $affectedResourceId = "0.0";
           $symb = 'a';
           $paramlevel = 'general';
       } elsif ($vars->{GRANULARITY} eq 'map') {
           my $navmap = Apache::lonnavmaps::navmap->new();
           my $res = $navmap->getByMapPc($vars->{RESOURCE_ID});
           my $title = $res->compTitle();
           $symb = $res->symb();
           $navmap->untieHashes();
           $resourceString .= "<li>for the map named <b>$title</b></li>";
           $level = 8;
           $affectedResourceId = $vars->{RESOURCE_ID};
           $paramlevel = 'map';
       } else {
           my $navmap = Apache::lonnavmaps::navmap->new();
           my $res = $navmap->getById($vars->{RESOURCE_ID});
           $symb = $res->symb();
           my $title = $res->compTitle();
           $navmap->untieHashes();
           $resourceString .= "<li>for the resource named <b>$title</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";
       $result .= '<p>Confirm that this information is correct, then click &quot;Finish Wizard&quot; to complete setting the parameter.<ul>';
           
     # Print the type of manipulation:      # Print the type of manipulation:
     $result .= '<li>Setting the <b>' . $dateTypeHash{$vars->{ACTION_TYPE}}      $result .= '<li>Setting the <b>' . $dateTypeHash{$vars->{ACTION_TYPE}} . '</b>';
                . "</b></li>\n";      if ($vars->{ACTION_TYPE} eq 'tries') {
    $result .= ' to <b>' . $vars->{TRIES} . '</b>';
       }
       $result .= "</li>\n";
     if ($vars->{ACTION_TYPE} eq 'due_date' ||       if ($vars->{ACTION_TYPE} eq 'due_date' || 
         $vars->{ACTION_TYPE} eq 'answer_date') {          $vars->{ACTION_TYPE} eq 'answer_date') {
         # for due dates, we default to "date end" type entries          # for due dates, we default to "date end" type entries
Line 2434  sub render { Line 2948  sub render {
             "value='" . $vars->{PARM_DATE} . "' />\n";              "value='" . $vars->{PARM_DATE} . "' />\n";
         $result .= "<input type='hidden' name='pres_type' " .          $result .= "<input type='hidden' name='pres_type' " .
             "value='date_start' />\n";              "value='date_start' />\n";
     }       } elsif ($vars->{ACTION_TYPE} eq 'tries') {
        $result .= "<input type='hidden' name='pres_value' " .
     # Print the granularity, depending on the action      "value='" . $vars->{TRIES} . "' />\n";
     if ($vars->{GRANULARITY} eq 'whole_course') {  
         $result .= '<li>for <b>all resources in the course</b></li>';  
         $level = 9; # general course, see lonparmset.pm perldoc  
         $affectedResourceId = "0.0";  
     } 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 $res = $navmap->getById($vars->{RESOURCE_ID});  
         my $title = $res->compTitle();  
         $navmap->untieHashes();  
         $result .= "<li>for the map named <b>$title</b></li>";  
         $level = 8;  
         $affectedResourceId = $vars->{RESOURCE_ID};  
     } else {  
         my $navmap = Apache::lonnavmaps::navmap->new(  
                            $ENV{"request.course.fn"}.".db",  
                            $ENV{"request.course.fn"}."_parms.db", 0, 0);  
         my $res = $navmap->getById($vars->{RESOURCE_ID});  
         my $title = $res->compTitle();  
         $navmap->untieHashes();  
         $result .= "<li>for the resource named <b>$title</b></li>";  
         $level = 7;  
         $affectedResourceId = $vars->{RESOURCE_ID};  
     }      }
   
       $result .= $resourceString;
       
     # Print targets      # Print targets
     if ($vars->{TARGETS} eq 'course') {      if ($vars->{TARGETS} eq 'course') {
         $result .= '<li>for <b>all students in course</b></li>';          $result .= '<li>for <b>all students in course</b></li>';
Line 2475  sub render { Line 2967  sub render {
     } else {      } else {
         # FIXME: This is probably wasteful! Store the name!          # FIXME: This is probably wasteful! Store the name!
         my $classlist = Apache::loncoursedata::get_classlist();          my $classlist = Apache::loncoursedata::get_classlist();
         my $name = $classlist->{$vars->{USER_NAME}}->[6];          my $username = $vars->{USER_NAME};
           # Chop off everything after the last colon (section)
           $username = substr($username, 0, rindex($username, ':'));
           my $name = $classlist->{$username}->[6];
         $result .= "<li>for <b>$name</b></li>";          $result .= "<li>for <b>$name</b></li>";
         $level -= 6;          $level -= 6;
         my ($uname, $udom) = split /:/, $vars->{USER_NAME};          my ($uname, $udom) = split /:/, $vars->{USER_NAME};
Line 2486  sub render { Line 2981  sub render {
     }      }
   
     # Print value      # Print value
     $result .= "<li>to <b>" . ctime($vars->{PARM_DATE}) . "</b> (" .      if ($vars->{ACTION_TYPE} ne 'tries') {
         Apache::lonnavmaps::timeToHumanString($vars->{PARM_DATE})    $result .= "<li>to <b>" . ctime($vars->{PARM_DATE}) . "</b> (" .
         . ")</li>\n";      Apache::lonnavmaps::timeToHumanString($vars->{PARM_DATE}) 
       . ")</li>\n";
       }
    
     # print pres_marker      # print pres_marker
     $result .= "\n<input type='hidden' name='pres_marker'" .      $result .= "\n<input type='hidden' name='pres_marker'" .
         " value='$affectedResourceId&$parm_name&$level' />\n";          " value='$affectedResourceId&$parm_name&$level' />\n";
       
       # 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' />";
   
     $result .= "<br /><br /><center><input type='submit' value='Finish Helper' /></center></form>\n";      $result .= "<br /><br /><center><input type='submit' value='Finish Helper' /></center></form>\n";
   

Removed from v.1.26  
changed lines
  Added in v.1.43


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>