Annotation of loncom/interface/lonhelper.pm, revision 1.92

1.1       bowersj2    1: # The LearningOnline Network with CAPA
                      2: # .helper XML handler to implement the LON-CAPA helper
                      3: #
1.92    ! foxr        4: # $Id: lonhelper.pm,v 1.91 2005/01/05 12:07:27 foxr Exp $
1.1       bowersj2    5: #
                      6: # Copyright Michigan State University Board of Trustees
                      7: #
                      8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
                      9: #
                     10: # LON-CAPA is free software; you can redistribute it and/or modify
                     11: # it under the terms of the GNU General Public License as published by
                     12: # the Free Software Foundation; either version 2 of the License, or
                     13: # (at your option) any later version.
                     14: #
                     15: # LON-CAPA is distributed in the hope that it will be useful,
                     16: # but WITHOUT ANY WARRANTY; without even the implied warranty of
                     17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     18: # GNU General Public License for more details.
                     19: #
                     20: # You should have received a copy of the GNU General Public License
                     21: # along with LON-CAPA; if not, write to the Free Software
                     22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                     23: #
                     24: # /home/httpd/html/adm/gpl.txt
                     25: #
                     26: # http://www.lon-capa.org/
                     27: #
                     28: # (Page Handler
                     29: #
                     30: # (.helper handler
                     31: #
                     32: 
1.3       bowersj2   33: =pod
                     34: 
1.44      bowersj2   35: =head1 NAME
1.3       bowersj2   36: 
1.44      bowersj2   37: lonhelper - implements helper framework
                     38: 
                     39: =head1 SYNOPSIS
                     40: 
                     41: lonhelper implements the helper framework for LON-CAPA, and provides
                     42:     many generally useful components for that framework.
                     43: 
                     44: Helpers are little programs which present the user with a sequence of
                     45:     simple choices, instead of one monolithic multi-dimensional
                     46:     choice. They are also referred to as "wizards", "druids", and
                     47:     other potentially trademarked or semantically-loaded words.
                     48: 
                     49: =head1 OVERVIEWX<lonhelper>
                     50: 
                     51: Helpers are well-established UI widgets that users
1.3       bowersj2   52: feel comfortable with. It can take a complicated multidimensional problem the
                     53: user has and turn it into a series of bite-sized one-dimensional questions.
                     54: 
                     55: For developers, helpers provide an easy way to bundle little bits of functionality
                     56: for the user, without having to write the tedious state-maintenence code.
                     57: 
                     58: Helpers are defined as XML documents, placed in the /home/httpd/html/adm/helpers 
                     59: directory and having the .helper file extension. For examples, see that directory.
                     60: 
                     61: All classes are in the Apache::lonhelper namespace.
                     62: 
1.44      bowersj2   63: =head1 lonhelper XML file formatX<lonhelper, XML file format>
1.3       bowersj2   64: 
                     65: A helper consists of a top-level <helper> tag which contains a series of states.
                     66: Each state contains one or more state elements, which are what the user sees, like
                     67: messages, resource selections, or date queries.
                     68: 
                     69: The helper tag is required to have one attribute, "title", which is the name
1.31      bowersj2   70: of the helper itself, such as "Parameter helper". The helper tag may optionally
                     71: have a "requiredpriv" attribute, specifying the priviledge a user must have
                     72: to use the helper, or get denied access. See loncom/auth/rolesplain.tab for
                     73: useful privs. Default is full access, which is often wrong!
1.3       bowersj2   74: 
                     75: =head2 State tags
                     76: 
                     77: State tags are required to have an attribute "name", which is the symbolic
1.7       bowersj2   78: name of the state and will not be directly seen by the user. The helper is
                     79: required to have one state named "START", which is the state the helper
1.5       bowersj2   80: will start with. By convention, this state should clearly describe what
1.3       bowersj2   81: the helper will do for the user, and may also include the first information
                     82: entry the user needs to do for the helper.
                     83: 
                     84: State tags are also required to have an attribute "title", which is the
                     85: human name of the state, and will be displayed as the header on top of 
                     86: the screen for the user.
                     87: 
                     88: =head2 Example Helper Skeleton
                     89: 
                     90: An example of the tags so far:
                     91: 
                     92:  <helper title="Example Helper">
                     93:    <state name="START" title="Demonstrating the Example Helper">
                     94:      <!-- notice this is the START state the wizard requires -->
                     95:      </state>
                     96:    <state name="GET_NAME" title="Enter Student Name">
                     97:      </state>
                     98:    </helper>
                     99: 
                    100: Of course this does nothing. In order for the wizard to do something, it is
                    101: necessary to put actual elements into the wizard. Documentation for each
                    102: of these elements follows.
                    103: 
1.44      bowersj2  104: =head1 Creating a Helper With Code, Not XML
1.13      bowersj2  105: 
                    106: In some situations, such as the printing wizard (see lonprintout.pm), 
                    107: writing the helper in XML would be too complicated, because of scope 
                    108: issues or the fact that the code actually outweighs the XML. It is
                    109: possible to create a helper via code, though it is a little odd.
                    110: 
                    111: Creating a helper via code is more like issuing commands to create
                    112: a helper then normal code writing. For instance, elements will automatically
                    113: be added to the last state created, so it's important to create the 
                    114: states in the correct order.
                    115: 
                    116: First, create a new helper:
                    117: 
                    118:  use Apache::lonhelper;
                    119: 
                    120:  my $helper = Apache::lonhelper::new->("Helper Title");
                    121: 
                    122: Next you'll need to manually add states to the helper:
                    123: 
                    124:  Apache::lonhelper::state->new("STATE_NAME", "State's Human Title");
                    125: 
                    126: You don't need to save a reference to it because all elements up until
                    127: the next state creation will automatically be added to this state.
                    128: 
                    129: Elements are created by populating the $paramHash in 
                    130: Apache::lonhelper::paramhash. To prevent namespace issues, retrieve 
                    131: a reference to that has with getParamHash:
                    132: 
                    133:  my $paramHash = Apache::lonhelper::getParamHash();
                    134: 
                    135: You will need to do this for each state you create.
                    136: 
                    137: Populate the $paramHash with the parameters for the element you wish
                    138: to add next; the easiest way to find out what those entries are is
                    139: to read the code. Some common ones are 'variable' to record the variable
                    140: to store the results in, and NEXTSTATE to record a next state transition.
                    141: 
                    142: Then create your element:
                    143: 
                    144:  $paramHash->{MESSAGETEXT} = "This is a message.";
                    145:  Apache::lonhelper::message->new();
                    146: 
                    147: The creation will take the $paramHash and bless it into a
                    148: Apache::lonhelper::message object. To create the next element, you need
                    149: to get a reference to the new, empty $paramHash:
                    150: 
                    151:  $paramHash = Apache::lonhelper::getParamHash();
                    152: 
                    153: and you can repeat creating elements that way. You can add states
                    154: and elements as needed.
                    155: 
                    156: See lonprintout.pm, subroutine printHelper for an example of this, where
                    157: we dynamically add some states to prevent security problems, for instance.
                    158: 
                    159: Normally the machinery in the XML format is sufficient; dynamically 
                    160: adding states can easily be done by wrapping the state in a <condition>
                    161: tag. This should only be used when the code dominates the XML content,
                    162: the code is so complicated that it is difficult to get access to
1.44      bowersj2  163: all of the information you need because of scoping issues, or would-be <exec> or 
                    164: <eval> blocks using the {DATA} mechanism results in hard-to-read
                    165: and -maintain code. (See course.initialization.helper for a borderline
                    166: case.)
1.13      bowersj2  167: 
                    168: It is possible to do some of the work with an XML fragment parsed by
1.17      bowersj2  169: lonxml; again, see lonprintout.pm for an example. In that case it is 
                    170: imperative that you call B<Apache::lonhelper::registerHelperTags()>
                    171: before parsing XML fragments and B<Apache::lonhelper::unregisterHelperTags()>
                    172: when you are done. See lonprintout.pm for examples of this usage in the
                    173: printHelper subroutine.
1.13      bowersj2  174: 
1.57      albertel  175: =head2 Localization
                    176: 
                    177: The helper framework tries to handle as much localization as
                    178: possible. The text is always run through
                    179: Apache::lonlocal::normalize_string, so be sure to run the keys through
                    180: that function for maximum usefulness and robustness.
                    181: 
1.3       bowersj2  182: =cut
                    183: 
1.1       bowersj2  184: package Apache::lonhelper;
1.2       bowersj2  185: use Apache::Constants qw(:common);
                    186: use Apache::File;
1.3       bowersj2  187: use Apache::lonxml;
1.57      albertel  188: use Apache::lonlocal;
1.2       bowersj2  189: 
1.7       bowersj2  190: # Register all the tags with the helper, so the helper can 
                    191: # push and pop them
                    192: 
                    193: my @helperTags;
                    194: 
                    195: sub register {
                    196:     my ($namespace, @tags) = @_;
                    197: 
                    198:     for my $tag (@tags) {
                    199:         push @helperTags, [$namespace, $tag];
                    200:     }
                    201: }
                    202: 
1.2       bowersj2  203: BEGIN {
1.7       bowersj2  204:     Apache::lonxml::register('Apache::lonhelper', 
                    205:                              ('helper'));
                    206:       register('Apache::lonhelper', ('state'));
1.2       bowersj2  207: }
                    208: 
1.7       bowersj2  209: # Since all helpers are only three levels deep (helper tag, state tag, 
1.3       bowersj2  210: # substate type), it's easier and more readble to explicitly track 
                    211: # those three things directly, rather then futz with the tag stack 
                    212: # every time.
                    213: my $helper;
                    214: my $state;
                    215: my $substate;
1.4       bowersj2  216: # To collect parameters, the contents of the subtags are collected
                    217: # into this paramHash, then passed to the element object when the 
                    218: # end of the element tag is located.
                    219: my $paramHash; 
1.2       bowersj2  220: 
1.25      bowersj2  221: # Note from Jeremy 5-8-2003: It is *vital* that the real handler be called
                    222: # as a subroutine from the handler, or very mysterious things might happen.
                    223: # I don't know exactly why, but it seems that the scope where the Apache
                    224: # server enters the perl handler is treated differently from the rest of
                    225: # the handler. This also seems to manifest itself in the debugger as entering
                    226: # the perl handler in seemingly random places (sometimes it starts in the
                    227: # compiling phase, sometimes in the handler execution phase where it runs
                    228: # the code and stepping into the "1;" the module ends with goes into the handler,
                    229: # sometimes starting directly with the handler); I think the cause is related.
                    230: # In the debugger, this means that breakpoints are ignored until you step into
                    231: # a function and get out of what must be a "faked up scope" in the Apache->
                    232: # mod_perl connection. In this code, it was manifesting itself in the existence
1.65      www       233: # of two separate file-scoped $helper variables, one set to the value of the
1.25      bowersj2  234: # helper in the helper constructor, and one referenced by the handler on the
1.44      bowersj2  235: # "$helper->process()" line. Using the debugger, one could actually
                    236: # see the two different $helper variables, as hashes at completely
                    237: # different addresses. The second was therefore never set, and was still
1.25      bowersj2  238: # undefined when I tried to call process on it.
                    239: # By pushing the "real handler" down into the "real scope", everybody except the 
                    240: # actual handler function directly below this comment gets the same $helper and
                    241: # everybody is happy.
                    242: # The upshot of all of this is that for safety when a handler is  using 
                    243: # file-scoped variables in LON-CAPA, the handler should be pushed down one 
                    244: # call level, as I do here, to ensure that the top-level handler function does
                    245: # not get a different file scope from the rest of the code.
                    246: sub handler {
                    247:     my $r = shift;
                    248:     return real_handler($r);
                    249: }
                    250: 
1.13      bowersj2  251: # For debugging purposes, one can send a second parameter into this
                    252: # function, the 'uri' of the helper you wish to have rendered, and
                    253: # call this from other handlers.
1.25      bowersj2  254: sub real_handler {
1.3       bowersj2  255:     my $r = shift;
1.13      bowersj2  256:     my $uri = shift;
                    257:     if (!defined($uri)) { $uri = $r->uri(); }
                    258:     $ENV{'request.uri'} = $uri;
                    259:     my $filename = '/home/httpd/html' . $uri;
1.2       bowersj2  260:     my $fh = Apache::File->new($filename);
                    261:     my $file;
1.3       bowersj2  262:     read $fh, $file, 100000000;
                    263: 
1.27      bowersj2  264: 
1.3       bowersj2  265:     # Send header, don't cache this page
1.70      sakharuk  266:     if ($ENV{'browser.mathml'}) {
                    267: 	&Apache::loncommon::content_type($r,'text/xml');
                    268:     } else {
                    269: 	&Apache::loncommon::content_type($r,'text/html');
                    270:     }
                    271:     $r->send_http_header;
                    272:     return OK if $r->header_only;
1.3       bowersj2  273:     $r->rflush();
1.2       bowersj2  274: 
1.3       bowersj2  275:     # Discard result, we just want the objects that get created by the
                    276:     # xml parsing
                    277:     &Apache::lonxml::xmlparse($r, 'helper', $file);
1.2       bowersj2  278: 
1.31      bowersj2  279:     my $allowed = $helper->allowedCheck();
                    280:     if (!$allowed) {
                    281:         $ENV{'user.error.msg'} = $ENV{'request.uri'}.':'.$helper->{REQUIRED_PRIV}.
                    282:             ":0:0:Permission denied to access this helper.";
                    283:         return HTTP_NOT_ACCEPTABLE;
                    284:     }
                    285: 
1.13      bowersj2  286:     $helper->process();
                    287: 
1.3       bowersj2  288:     $r->print($helper->display());
1.31      bowersj2  289:     return OK;
1.2       bowersj2  290: }
                    291: 
1.13      bowersj2  292: sub registerHelperTags {
                    293:     for my $tagList (@helperTags) {
                    294:         Apache::lonxml::register($tagList->[0], $tagList->[1]);
                    295:     }
                    296: }
                    297: 
                    298: sub unregisterHelperTags {
                    299:     for my $tagList (@helperTags) {
                    300:         Apache::lonxml::deregister($tagList->[0], $tagList->[1]);
                    301:     }
                    302: }
                    303: 
1.2       bowersj2  304: sub start_helper {
                    305:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                    306: 
                    307:     if ($target ne 'helper') {
                    308:         return '';
                    309:     }
1.7       bowersj2  310: 
1.13      bowersj2  311:     registerHelperTags();
                    312: 
1.31      bowersj2  313:     Apache::lonhelper::helper->new($token->[2]{'title'}, $token->[2]{'requiredpriv'});
1.4       bowersj2  314:     return '';
1.2       bowersj2  315: }
                    316: 
                    317: sub end_helper {
                    318:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                    319:     
1.3       bowersj2  320:     if ($target ne 'helper') {
                    321:         return '';
                    322:     }
1.7       bowersj2  323: 
1.13      bowersj2  324:     unregisterHelperTags();
1.7       bowersj2  325: 
1.4       bowersj2  326:     return '';
1.2       bowersj2  327: }
1.1       bowersj2  328: 
1.3       bowersj2  329: sub start_state {
                    330:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                    331: 
                    332:     if ($target ne 'helper') {
                    333:         return '';
                    334:     }
                    335: 
1.13      bowersj2  336:     Apache::lonhelper::state->new($token->[2]{'name'},
                    337:                                   $token->[2]{'title'});
1.3       bowersj2  338:     return '';
                    339: }
                    340: 
1.13      bowersj2  341: # Use this to get the param hash from other files.
                    342: sub getParamHash {
                    343:     return $paramHash;
                    344: }
                    345: 
                    346: # Use this to get the helper, if implementing elements in other files
                    347: # (like lonprintout.pm)
                    348: sub getHelper {
                    349:     return $helper;
                    350: }
                    351: 
1.3       bowersj2  352: # don't need this, so ignore it
                    353: sub end_state {
                    354:     return '';
                    355: }
                    356: 
1.1       bowersj2  357: 1;
                    358: 
1.3       bowersj2  359: package Apache::lonhelper::helper;
                    360: 
                    361: use Digest::MD5 qw(md5_hex);
1.57      albertel  362: use HTML::Entities();
1.3       bowersj2  363: use Apache::loncommon;
                    364: use Apache::File;
1.57      albertel  365: use Apache::lonlocal;
1.3       bowersj2  366: 
                    367: sub new {
                    368:     my $proto = shift;
                    369:     my $class = ref($proto) || $proto;
                    370:     my $self = {};
                    371: 
                    372:     $self->{TITLE} = shift;
1.31      bowersj2  373:     $self->{REQUIRED_PRIV} = shift;
1.3       bowersj2  374:     
                    375:     # If there is a state from the previous form, use that. If there is no
                    376:     # state, use the start state parameter.
                    377:     if (defined $ENV{"form.CURRENT_STATE"})
                    378:     {
                    379: 	$self->{STATE} = $ENV{"form.CURRENT_STATE"};
                    380:     }
                    381:     else
                    382:     {
                    383: 	$self->{STATE} = "START";
                    384:     }
                    385: 
                    386:     $self->{TOKEN} = $ENV{'form.TOKEN'};
                    387:     # If a token was passed, we load that in. Otherwise, we need to create a 
                    388:     # new storage file
                    389:     # Tried to use standard Tie'd hashes, but you can't seem to take a 
                    390:     # reference to a tied hash and write to it. I'd call that a wart.
                    391:     if ($self->{TOKEN}) {
                    392:         # Validate the token before trusting it
                    393:         if ($self->{TOKEN} !~ /^[a-f0-9]{32}$/) {
                    394:             # Not legit. Return nothing and let all hell break loose.
                    395:             # User shouldn't be doing that!
                    396:             return undef;
                    397:         }
                    398: 
                    399:         # Get the hash.
                    400:         $self->{FILENAME} = $Apache::lonnet::tmpdir . md5_hex($self->{TOKEN}); # Note the token is not the literal file
                    401:         
                    402:         my $file = Apache::File->new($self->{FILENAME});
                    403:         my $contents = <$file>;
1.5       bowersj2  404: 
                    405:         # Now load in the contents
                    406:         for my $value (split (/&/, $contents)) {
                    407:             my ($name, $value) = split(/=/, $value);
                    408:             $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
                    409:             $self->{VARS}->{$name} = $value;
                    410:         }
                    411: 
1.3       bowersj2  412:         $file->close();
                    413:     } else {
                    414:         # Only valid if we're just starting.
                    415:         if ($self->{STATE} ne 'START') {
                    416:             return undef;
                    417:         }
                    418:         # Must create the storage
                    419:         $self->{TOKEN} = md5_hex($ENV{'user.name'} . $ENV{'user.domain'} .
                    420:                                  time() . rand());
                    421:         $self->{FILENAME} = $Apache::lonnet::tmpdir . md5_hex($self->{TOKEN});
                    422:     }
                    423: 
                    424:     # OK, we now have our persistent storage.
                    425: 
                    426:     if (defined $ENV{"form.RETURN_PAGE"})
                    427:     {
                    428: 	$self->{RETURN_PAGE} = $ENV{"form.RETURN_PAGE"};
                    429:     }
                    430:     else
                    431:     {
                    432: 	$self->{RETURN_PAGE} = $ENV{REFERER};
                    433:     }
                    434: 
                    435:     $self->{STATES} = {};
                    436:     $self->{DONE} = 0;
                    437: 
1.9       bowersj2  438:     # Used by various helpers for various things; see lonparm.helper
                    439:     # for an example.
                    440:     $self->{DATA} = {};
                    441: 
1.13      bowersj2  442:     $helper = $self;
                    443: 
                    444:     # Establish the $paramHash
                    445:     $paramHash = {};
                    446: 
1.3       bowersj2  447:     bless($self, $class);
                    448:     return $self;
                    449: }
                    450: 
                    451: # Private function; returns a string to construct the hidden fields
                    452: # necessary to have the helper track state.
                    453: sub _saveVars {
                    454:     my $self = shift;
                    455:     my $result = "";
                    456:     $result .= '<input type="hidden" name="CURRENT_STATE" value="' .
1.67      albertel  457:         HTML::Entities::encode($self->{STATE},'<>&"') . "\" />\n";
1.3       bowersj2  458:     $result .= '<input type="hidden" name="TOKEN" value="' .
                    459:         $self->{TOKEN} . "\" />\n";
                    460:     $result .= '<input type="hidden" name="RETURN_PAGE" value="' .
1.67      albertel  461:         HTML::Entities::encode($self->{RETURN_PAGE},'<>&"') . "\" />\n";
1.3       bowersj2  462: 
                    463:     return $result;
                    464: }
                    465: 
                    466: # Private function: Create the querystring-like representation of the stored
                    467: # data to write to disk.
                    468: sub _varsInFile {
                    469:     my $self = shift;
                    470:     my @vars = ();
                    471:     for my $key (keys %{$self->{VARS}}) {
                    472:         push @vars, &Apache::lonnet::escape($key) . '=' .
                    473:             &Apache::lonnet::escape($self->{VARS}->{$key});
                    474:     }
                    475:     return join ('&', @vars);
                    476: }
                    477: 
1.5       bowersj2  478: # Use this to declare variables.
                    479: # FIXME: Document this
                    480: sub declareVar {
                    481:     my $self = shift;
                    482:     my $var = shift;
                    483: 
                    484:     if (!defined($self->{VARS}->{$var})) {
                    485:         $self->{VARS}->{$var} = '';
                    486:     }
                    487: 
                    488:     my $envname = 'form.' . $var . '.forminput';
                    489:     if (defined($ENV{$envname})) {
1.28      bowersj2  490:         if (ref($ENV{$envname})) {
                    491:             $self->{VARS}->{$var} = join('|||', @{$ENV{$envname}});
                    492:         } else {
                    493:             $self->{VARS}->{$var} = $ENV{$envname};
                    494:         }
1.5       bowersj2  495:     }
                    496: }
                    497: 
1.31      bowersj2  498: sub allowedCheck {
                    499:     my $self = shift;
                    500: 
                    501:     if (!defined($self->{REQUIRED_PRIV})) { 
                    502:         return 1;
                    503:     }
                    504: 
                    505:     return Apache::lonnet::allowed($self->{REQUIRED_PRIV}, $ENV{'request.course.id'});
                    506: }
                    507: 
1.3       bowersj2  508: sub changeState {
                    509:     my $self = shift;
                    510:     $self->{STATE} = shift;
                    511: }
                    512: 
                    513: sub registerState {
                    514:     my $self = shift;
                    515:     my $state = shift;
                    516: 
                    517:     my $stateName = $state->name();
                    518:     $self->{STATES}{$stateName} = $state;
                    519: }
                    520: 
1.13      bowersj2  521: sub process {
1.3       bowersj2  522:     my $self = shift;
                    523: 
                    524:     # Phase 1: Post processing for state of previous screen (which is actually
                    525:     # the "current state" in terms of the helper variables), if it wasn't the 
                    526:     # beginning state.
1.57      albertel  527:     if ($self->{STATE} ne "START" || $ENV{"form.SUBMIT"} eq &mt("Next ->")) {
1.3       bowersj2  528: 	my $prevState = $self->{STATES}{$self->{STATE}};
1.13      bowersj2  529:         $prevState->postprocess();
1.3       bowersj2  530:     }
                    531:     
                    532:     # Note, to handle errors in a state's input that a user must correct,
                    533:     # do not transition in the postprocess, and force the user to correct
                    534:     # the error.
                    535: 
                    536:     # Phase 2: Preprocess current state
                    537:     my $startState = $self->{STATE};
1.17      bowersj2  538:     my $state = $self->{STATES}->{$startState};
1.3       bowersj2  539:     
1.13      bowersj2  540:     # For debugging, print something here to determine if you're going
                    541:     # to an undefined state.
1.3       bowersj2  542:     if (!defined($state)) {
1.13      bowersj2  543:         return;
1.3       bowersj2  544:     }
                    545:     $state->preprocess();
                    546: 
                    547:     # Phase 3: While the current state is different from the previous state,
                    548:     # keep processing.
1.17      bowersj2  549:     while ( $startState ne $self->{STATE} && 
                    550:             defined($self->{STATES}->{$self->{STATE}}) )
1.3       bowersj2  551:     {
                    552: 	$startState = $self->{STATE};
1.17      bowersj2  553: 	$state = $self->{STATES}->{$startState};
1.3       bowersj2  554: 	$state->preprocess();
                    555:     }
                    556: 
1.13      bowersj2  557:     return;
                    558: } 
                    559: 
                    560: # 1: Do the post processing for the previous state.
                    561: # 2: Do the preprocessing for the current state.
                    562: # 3: Check to see if state changed, if so, postprocess current and move to next.
                    563: #    Repeat until state stays stable.
                    564: # 4: Render the current state to the screen as an HTML page.
                    565: sub display {
                    566:     my $self = shift;
                    567: 
                    568:     my $state = $self->{STATES}{$self->{STATE}};
                    569: 
                    570:     my $result = "";
                    571: 
1.17      bowersj2  572:     if (!defined($state)) {
                    573:         $result = "<font color='#ff0000'>Error: state '$state' not defined!</font>";
                    574:         return $result;
                    575:     }
                    576: 
1.3       bowersj2  577:     # Phase 4: Display.
1.68      sakharuk  578:     my $stateTitle=&mt($state->title());
1.57      albertel  579:     my $helperTitle = &mt($self->{TITLE});
                    580:     my $bodytag = &Apache::loncommon::bodytag($helperTitle,'','');
                    581:     my $previous = HTML::Entities::encode(&mt("<- Previous"), '<>&"');
                    582:     my $next = HTML::Entities::encode(&mt("Next ->"), '<>&"');
                    583:     # FIXME: This should be parameterized, not concatenated - Jeremy
                    584:     my $loncapaHelper = &mt("LON-CAPA Helper:");
1.3       bowersj2  585: 
                    586:     $result .= <<HEADER;
                    587: <html>
                    588:     <head>
1.57      albertel  589:         <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
                    590:         <title>$loncapaHelper: $helperTitle</title>
1.3       bowersj2  591:     </head>
                    592:     $bodytag
                    593: HEADER
1.28      bowersj2  594:     if (!$state->overrideForm()) { $result.="<form name='helpform' method='POST'>"; }
1.3       bowersj2  595:     $result .= <<HEADER;
1.31      bowersj2  596:         <table border="0" width='100%'><tr><td>
1.3       bowersj2  597:         <h2><i>$stateTitle</i></h2>
                    598: HEADER
                    599: 
1.31      bowersj2  600:     $result .= "<table cellpadding='10' width='100%'><tr><td rowspan='2' valign='top'>";
1.30      bowersj2  601: 
1.3       bowersj2  602:     if (!$state->overrideForm()) {
                    603:         $result .= $self->_saveVars();
                    604:     }
1.30      bowersj2  605:     $result .= $state->render();
                    606: 
1.31      bowersj2  607:     $result .= "</td><td valign='top' align='right'>";
1.3       bowersj2  608: 
1.30      bowersj2  609:     # Warning: Copy and pasted from below, because it's too much trouble to 
                    610:     # turn this into a subroutine
1.3       bowersj2  611:     if (!$state->overrideForm()) {
                    612:         if ($self->{STATE} ne $self->{START_STATE}) {
                    613:             #$result .= '<input name="SUBMIT" type="submit" value="&lt;- Previous" />&nbsp;&nbsp;';
                    614:         }
                    615:         if ($self->{DONE}) {
                    616:             my $returnPage = $self->{RETURN_PAGE};
1.57      albertel  617:             $result .= "<a href=\"$returnPage\">" . &mt("End Helper") . "</a>";
1.3       bowersj2  618:         }
                    619:         else {
1.30      bowersj2  620:             $result .= '<nobr><input name="back" type="button" ';
1.57      albertel  621:             $result .= 'value="' . $previous . '" onclick="history.go(-1)" /> ';
                    622:             $result .= '<input name="SUBMIT" type="submit" value="' . $next . '" /></nobr>';
1.30      bowersj2  623:         }
                    624:     }
                    625: 
1.31      bowersj2  626:     $result .= "</td></tr><tr><td valign='bottom' align='right'>";
1.30      bowersj2  627: 
                    628:     # Warning: Copy and pasted from above, because it's too much trouble to 
                    629:     # turn this into a subroutine
                    630:     if (!$state->overrideForm()) {
                    631:         if ($self->{STATE} ne $self->{START_STATE}) {
                    632:             #$result .= '<input name="SUBMIT" type="submit" value="&lt;- Previous" />&nbsp;&nbsp;';
                    633:         }
                    634:         if ($self->{DONE}) {
                    635:             my $returnPage = $self->{RETURN_PAGE};
1.57      albertel  636:             $result .= "<a href=\"$returnPage\">" . &mt('End Helper') . "</a>";
1.30      bowersj2  637:         }
                    638:         else {
                    639:             $result .= '<nobr><input name="back" type="button" ';
1.57      albertel  640:             $result .= 'value="' . $previous . '" onclick="history.go(-1)" /> ';
                    641:             $result .= '<input name="SUBMIT" type="submit" value="' . $next . '" /></nobr>';
1.3       bowersj2  642:         }
                    643:     }
                    644: 
1.13      bowersj2  645:     #foreach my $key (keys %{$self->{VARS}}) {
                    646:     #    $result .= "|$key| -> " . $self->{VARS}->{$key} . "<br />";
                    647:     #}
1.5       bowersj2  648: 
1.30      bowersj2  649:     $result .= "</td></tr></table>";
                    650: 
1.3       bowersj2  651:     $result .= <<FOOTER;
                    652:               </td>
                    653:             </tr>
                    654:           </table>
                    655:         </form>
                    656:     </body>
                    657: </html>
                    658: FOOTER
                    659: 
                    660:     # Handle writing out the vars to the file
                    661:     my $file = Apache::File->new('>'.$self->{FILENAME});
1.33      bowersj2  662:     print $file $self->_varsInFile();
1.3       bowersj2  663: 
                    664:     return $result;
                    665: }
                    666: 
                    667: 1;
                    668: 
                    669: package Apache::lonhelper::state;
                    670: 
                    671: # States bundle things together and are responsible for compositing the
1.4       bowersj2  672: # various elements together. It is not generally necessary for users to
                    673: # use the state object directly, so it is not perldoc'ed.
                    674: 
                    675: # Basically, all the states do is pass calls to the elements and aggregate
                    676: # the results.
1.3       bowersj2  677: 
                    678: sub new {
                    679:     my $proto = shift;
                    680:     my $class = ref($proto) || $proto;
                    681:     my $self = {};
                    682: 
                    683:     $self->{NAME} = shift;
                    684:     $self->{TITLE} = shift;
                    685:     $self->{ELEMENTS} = [];
                    686: 
                    687:     bless($self, $class);
                    688: 
                    689:     $helper->registerState($self);
                    690: 
1.13      bowersj2  691:     $state = $self;
                    692: 
1.3       bowersj2  693:     return $self;
                    694: }
                    695: 
                    696: sub name {
                    697:     my $self = shift;
                    698:     return $self->{NAME};
                    699: }
                    700: 
                    701: sub title {
                    702:     my $self = shift;
                    703:     return $self->{TITLE};
                    704: }
                    705: 
1.4       bowersj2  706: sub preprocess {
                    707:     my $self = shift;
                    708:     for my $element (@{$self->{ELEMENTS}}) {
                    709:         $element->preprocess();
                    710:     }
                    711: }
                    712: 
1.6       bowersj2  713: # FIXME: Document that all postprocesses must return a true value or
                    714: # the state transition will be overridden
1.4       bowersj2  715: sub postprocess {
                    716:     my $self = shift;
1.6       bowersj2  717: 
                    718:     # Save the state so we can roll it back if we need to.
                    719:     my $originalState = $helper->{STATE};
                    720:     my $everythingSuccessful = 1;
                    721: 
1.4       bowersj2  722:     for my $element (@{$self->{ELEMENTS}}) {
1.6       bowersj2  723:         my $result = $element->postprocess();
                    724:         if (!$result) { $everythingSuccessful = 0; }
                    725:     }
                    726: 
                    727:     # If not all the postprocesses were successful, override
                    728:     # any state transitions that may have occurred. It is the
                    729:     # responsibility of the states to make sure they have 
                    730:     # error handling in that case.
                    731:     if (!$everythingSuccessful) {
                    732:         $helper->{STATE} = $originalState;
1.4       bowersj2  733:     }
                    734: }
                    735: 
1.13      bowersj2  736: # Override the form if any element wants to.
                    737: # two elements overriding the form will make a mess, but that should
                    738: # be considered helper author error ;-)
1.4       bowersj2  739: sub overrideForm {
1.13      bowersj2  740:     my $self = shift;
                    741:     for my $element (@{$self->{ELEMENTS}}) {
                    742:         if ($element->overrideForm()) {
                    743:             return 1;
                    744:         }
                    745:     }
1.4       bowersj2  746:     return 0;
                    747: }
                    748: 
                    749: sub addElement {
                    750:     my $self = shift;
                    751:     my $element = shift;
                    752:     
                    753:     push @{$self->{ELEMENTS}}, $element;
                    754: }
                    755: 
                    756: sub render {
                    757:     my $self = shift;
                    758:     my @results = ();
                    759: 
                    760:     for my $element (@{$self->{ELEMENTS}}) {
                    761:         push @results, $element->render();
                    762:     }
1.28      bowersj2  763: 
1.4       bowersj2  764:     return join("\n", @results);
                    765: }
                    766: 
                    767: 1;
                    768: 
                    769: package Apache::lonhelper::element;
                    770: # Support code for elements
                    771: 
                    772: =pod
                    773: 
1.44      bowersj2  774: =head1 Element Base Class
1.4       bowersj2  775: 
1.28      bowersj2  776: The Apache::lonhelper::element base class provides support for elements
                    777: and defines some generally useful tags for use in elements.
1.4       bowersj2  778: 
1.44      bowersj2  779: =head2 finalcode tagX<finalcode>
1.25      bowersj2  780: 
                    781: Each element can contain a "finalcode" tag that, when the special FINAL
                    782: helper state is used, will be executed, surrounded by "sub { my $helper = shift;"
                    783: and "}". It is expected to return a string describing what it did, which 
                    784: may be an empty string. See course initialization helper for an example. This is
                    785: generally intended for helpers like the course initialization helper, which consist
                    786: of several panels, each of which is performing some sort of bite-sized functionality.
                    787: 
1.44      bowersj2  788: =head2 defaultvalue tagX<defaultvalue>
1.25      bowersj2  789: 
                    790: Each element that accepts user input can contain a "defaultvalue" tag that,
                    791: when surrounded by "sub { my $helper = shift; my $state = shift; " and "}",
                    792: will form a subroutine that when called will provide a default value for
                    793: the element. How this value is interpreted by the element is specific to
                    794: the element itself, and possibly the settings the element has (such as 
                    795: multichoice vs. single choice for <choices> tags). 
                    796: 
                    797: This is also intended for things like the course initialization wizard, where the
                    798: user is setting various parameters. By correctly grabbing current settings 
                    799: and including them into the helper, it allows the user to come back to the
                    800: helper later and re-execute it, without needing to worry about overwriting
                    801: some setting accidentally.
                    802: 
                    803: Again, see the course initialization helper for examples.
                    804: 
1.44      bowersj2  805: =head2 validator tagX<validator>
1.38      bowersj2  806: 
                    807: Some elements that accepts user input can contain a "validator" tag that,
                    808: when surrounded by "sub { my $helper = shift; my $state = shift; my $element = shift; my $val = shift " 
                    809: and "}", where "$val" is the value the user entered, will form a subroutine 
                    810: that when called will verify whether the given input is valid or not. If it 
                    811: is valid, the routine will return a false value. If invalid, the routine 
                    812: will return an error message to be displayed for the user.
                    813: 
                    814: Consult the documentation for each element to see whether it supports this 
                    815: tag.
                    816: 
1.44      bowersj2  817: =head2 getValue methodX<getValue (helper elements)>
1.31      bowersj2  818: 
                    819: If the element stores the name of the variable in a 'variable' member, which
                    820: the provided ones all do, you can retreive the value of the variable by calling
                    821: this method.
                    822: 
1.4       bowersj2  823: =cut
                    824: 
1.5       bowersj2  825: BEGIN {
1.7       bowersj2  826:     &Apache::lonhelper::register('Apache::lonhelper::element',
1.25      bowersj2  827:                                  ('nextstate', 'finalcode',
1.38      bowersj2  828:                                   'defaultvalue', 'validator'));
1.5       bowersj2  829: }
                    830: 
1.4       bowersj2  831: # Because we use the param hash, this is often a sufficent
                    832: # constructor
                    833: sub new {
                    834:     my $proto = shift;
                    835:     my $class = ref($proto) || $proto;
                    836:     my $self = $paramHash;
                    837:     bless($self, $class);
                    838: 
                    839:     $self->{PARAMS} = $paramHash;
                    840:     $self->{STATE} = $state;
                    841:     $state->addElement($self);
                    842:     
                    843:     # Ensure param hash is not reused
                    844:     $paramHash = {};
                    845: 
                    846:     return $self;
                    847: }   
                    848: 
1.5       bowersj2  849: sub start_nextstate {
                    850:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                    851: 
                    852:     if ($target ne 'helper') {
                    853:         return '';
                    854:     }
                    855:     
                    856:     $paramHash->{NEXTSTATE} = &Apache::lonxml::get_all_text('/nextstate',
                    857:                                                              $parser);
                    858:     return '';
                    859: }
                    860: 
                    861: sub end_nextstate { return ''; }
                    862: 
1.25      bowersj2  863: sub start_finalcode {
                    864:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                    865: 
                    866:     if ($target ne 'helper') {
                    867:         return '';
                    868:     }
                    869:     
                    870:     $paramHash->{FINAL_CODE} = &Apache::lonxml::get_all_text('/finalcode',
                    871:                                                              $parser);
                    872:     return '';
                    873: }
                    874: 
                    875: sub end_finalcode { return ''; }
                    876: 
                    877: sub start_defaultvalue {
                    878:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                    879: 
                    880:     if ($target ne 'helper') {
                    881:         return '';
                    882:     }
                    883:     
                    884:     $paramHash->{DEFAULT_VALUE} = &Apache::lonxml::get_all_text('/defaultvalue',
                    885:                                                              $parser);
                    886:     $paramHash->{DEFAULT_VALUE} = 'sub { my $helper = shift; my $state = shift;' .
                    887:         $paramHash->{DEFAULT_VALUE} . '}';
                    888:     return '';
                    889: }
                    890: 
                    891: sub end_defaultvalue { return ''; }
                    892: 
1.57      albertel  893: # Validators may need to take language specifications
1.38      bowersj2  894: sub start_validator {
                    895:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                    896: 
                    897:     if ($target ne 'helper') {
                    898:         return '';
                    899:     }
                    900:     
                    901:     $paramHash->{VALIDATOR} = &Apache::lonxml::get_all_text('/validator',
                    902:                                                              $parser);
                    903:     $paramHash->{VALIDATOR} = 'sub { my $helper = shift; my $state = shift; my $element = shift; my $val = shift;' .
                    904:         $paramHash->{VALIDATOR} . '}';
                    905:     return '';
                    906: }
                    907: 
                    908: sub end_validator { return ''; }
                    909: 
1.4       bowersj2  910: sub preprocess {
                    911:     return 1;
                    912: }
                    913: 
                    914: sub postprocess {
                    915:     return 1;
                    916: }
                    917: 
                    918: sub render {
                    919:     return '';
                    920: }
                    921: 
1.13      bowersj2  922: sub overrideForm {
                    923:     return 0;
                    924: }
                    925: 
1.31      bowersj2  926: sub getValue {
                    927:     my $self = shift;
                    928:     return $helper->{VARS}->{$self->{'variable'}};
                    929: }
                    930: 
1.4       bowersj2  931: 1;
                    932: 
                    933: package Apache::lonhelper::message;
                    934: 
                    935: =pod
                    936: 
1.48      bowersj2  937: =head1 Elements
                    938: 
                    939: =head2 Element: messageX<message, helper element>
1.4       bowersj2  940: 
1.44      bowersj2  941: Message elements display their contents, and
                    942: transition directly to the state in the <nextstate> attribute. Example:
1.4       bowersj2  943: 
1.44      bowersj2  944:  <message nextstate='GET_NAME'>
                    945:    This is the <b>message</b> the user will see, 
                    946:                  <i>HTML allowed</i>.
1.4       bowersj2  947:    </message>
                    948: 
1.44      bowersj2  949: This will display the HTML message and transition to the 'nextstate' if
1.7       bowersj2  950: given. The HTML will be directly inserted into the helper, so if you don't
1.44      bowersj2  951: want text to run together, you'll need to manually wrap the message text
1.4       bowersj2  952: in <p> tags, or whatever is appropriate for your HTML.
                    953: 
1.5       bowersj2  954: Message tags do not add in whitespace, so if you want it, you'll need to add
                    955: it into states. This is done so you can inline some elements, such as 
                    956: the <date> element, right between two messages, giving the appearence that 
                    957: the <date> element appears inline. (Note the elements can not be embedded
                    958: within each other.)
                    959: 
1.4       bowersj2  960: This is also a good template for creating your own new states, as it has
                    961: very little code beyond the state template.
                    962: 
1.57      albertel  963: =head3 Localization
                    964: 
                    965: The contents of the message tag will be run through the
                    966: normalize_string function and that will be used as a call to &mt.
                    967: 
1.4       bowersj2  968: =cut
                    969: 
                    970: no strict;
                    971: @ISA = ("Apache::lonhelper::element");
                    972: use strict;
1.57      albertel  973: use Apache::lonlocal;
1.4       bowersj2  974: 
                    975: BEGIN {
1.7       bowersj2  976:     &Apache::lonhelper::register('Apache::lonhelper::message',
1.10      bowersj2  977:                               ('message'));
1.3       bowersj2  978: }
                    979: 
1.5       bowersj2  980: sub new {
                    981:     my $ref = Apache::lonhelper::element->new();
                    982:     bless($ref);
                    983: }
1.4       bowersj2  984: 
                    985: # CONSTRUCTION: Construct the message element from the XML
                    986: sub start_message {
                    987:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                    988: 
                    989:     if ($target ne 'helper') {
                    990:         return '';
                    991:     }
1.10      bowersj2  992: 
1.69      sakharuk  993:     $paramHash->{MESSAGE_TEXT} = &mtn(&Apache::lonxml::get_all_text('/message',
                    994:                                                                $parser));
1.10      bowersj2  995: 
                    996:     if (defined($token->[2]{'nextstate'})) {
                    997:         $paramHash->{NEXTSTATE} = $token->[2]{'nextstate'};
                    998:     }
1.4       bowersj2  999:     return '';
1.3       bowersj2 1000: }
                   1001: 
1.10      bowersj2 1002: sub end_message {
1.4       bowersj2 1003:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   1004: 
                   1005:     if ($target ne 'helper') {
                   1006:         return '';
                   1007:     }
1.10      bowersj2 1008:     Apache::lonhelper::message->new();
                   1009:     return '';
1.5       bowersj2 1010: }
                   1011: 
                   1012: sub render {
                   1013:     my $self = shift;
                   1014: 
1.57      albertel 1015:     return &mtn($self->{MESSAGE_TEXT});
1.5       bowersj2 1016: }
                   1017: # If a NEXTSTATE was given, switch to it
                   1018: sub postprocess {
                   1019:     my $self = shift;
                   1020:     if (defined($self->{NEXTSTATE})) {
                   1021:         $helper->changeState($self->{NEXTSTATE});
                   1022:     }
1.6       bowersj2 1023: 
                   1024:     return 1;
1.5       bowersj2 1025: }
                   1026: 1;
                   1027: 
                   1028: package Apache::lonhelper::choices;
                   1029: 
                   1030: =pod
                   1031: 
1.44      bowersj2 1032: =head2 Element: choicesX<choices, helper element>
1.5       bowersj2 1033: 
                   1034: Choice states provide a single choice to the user as a text selection box.
                   1035: A "choice" is two pieces of text, one which will be displayed to the user
                   1036: (the "human" value), and one which will be passed back to the program
                   1037: (the "computer" value). For instance, a human may choose from a list of
                   1038: resources on disk by title, while your program wants the file name.
                   1039: 
                   1040: <choices> takes an attribute "variable" to control which helper variable
                   1041: the result is stored in.
                   1042: 
                   1043: <choices> takes an attribute "multichoice" which, if set to a true
                   1044: value, will allow the user to select multiple choices.
                   1045: 
1.26      bowersj2 1046: <choices> takes an attribute "allowempty" which, if set to a true 
                   1047: value, will allow the user to select none of the choices without raising
                   1048: an error message.
                   1049: 
1.44      bowersj2 1050: =head3 SUB-TAGS
1.5       bowersj2 1051: 
1.44      bowersj2 1052: <choices> can have the following subtags:X<choice, helper tag>
1.5       bowersj2 1053: 
                   1054: =over 4
                   1055: 
                   1056: =item * <nextstate>state_name</nextstate>: If given, this will cause the
1.44      bowersj2 1057:       choice element to transition to the given state after executing.
                   1058:       This will override the <nextstate> passed to <choices> (if any).
1.5       bowersj2 1059: 
                   1060: =item * <choice />: If the choices are static,
                   1061:       this element will allow you to specify them. Each choice
                   1062:       contains  attribute, "computer", as described above. The
                   1063:       content of the tag will be used as the human label.
                   1064:       For example,  
                   1065:       <choice computer='234-12-7312'>Bobby McDormik</choice>.
                   1066: 
1.44      bowersj2 1067: <choice> can take a parameter "eval", which if set to
                   1068: a true value, will cause the contents of the tag to be
                   1069: evaluated as it would be in an <eval> tag; see <eval> tag
                   1070: below.
1.13      bowersj2 1071: 
1.5       bowersj2 1072: <choice> may optionally contain a 'nextstate' attribute, which
1.44      bowersj2 1073: will be the state transistioned to if the choice is made, if
                   1074: the choice is not multichoice. This will override the nextstate
                   1075: passed to the parent C<choices> tag.
1.5       bowersj2 1076: 
                   1077: =back
                   1078: 
                   1079: To create the choices programmatically, either wrap the choices in 
                   1080: <condition> tags (prefered), or use an <exec> block inside the <choice>
                   1081: tag. Store the choices in $state->{CHOICES}, which is a list of list
                   1082: references, where each list has three strings. The first is the human
                   1083: name, the second is the computer name. and the third is the option
                   1084: next state. For example:
                   1085: 
                   1086:  <exec>
                   1087:     for (my $i = 65; $i < 65 + 26; $i++) {
                   1088:         push @{$state->{CHOICES}}, [chr($i), $i, 'next'];
                   1089:     }
                   1090:  </exec>
                   1091: 
                   1092: This will allow the user to select from the letters A-Z (in ASCII), while
                   1093: passing the ASCII value back into the helper variables, and the state
                   1094: will in all cases transition to 'next'.
                   1095: 
                   1096: You can mix and match methods of creating choices, as long as you always 
                   1097: "push" onto the choice list, rather then wiping it out. (You can even 
                   1098: remove choices programmatically, but that would probably be bad form.)
                   1099: 
1.44      bowersj2 1100: =head3 defaultvalue support
1.25      bowersj2 1101: 
                   1102: Choices supports default values both in multichoice and single choice mode.
                   1103: In single choice mode, have the defaultvalue tag's function return the 
                   1104: computer value of the box you want checked. If the function returns a value
                   1105: that does not correspond to any of the choices, the default behavior of selecting
                   1106: the first choice will be preserved.
                   1107: 
                   1108: For multichoice, return a string with the computer values you want checked,
                   1109: delimited by triple pipes. Note this matches how the result of the <choices>
                   1110: tag is stored in the {VARS} hash.
                   1111: 
1.5       bowersj2 1112: =cut
                   1113: 
                   1114: no strict;
                   1115: @ISA = ("Apache::lonhelper::element");
                   1116: use strict;
1.57      albertel 1117: use Apache::lonlocal;
1.5       bowersj2 1118: 
                   1119: BEGIN {
1.7       bowersj2 1120:     &Apache::lonhelper::register('Apache::lonhelper::choices',
1.5       bowersj2 1121:                               ('choice', 'choices'));
                   1122: }
                   1123: 
                   1124: sub new {
                   1125:     my $ref = Apache::lonhelper::element->new();
                   1126:     bless($ref);
                   1127: }
                   1128: 
                   1129: # CONSTRUCTION: Construct the message element from the XML
                   1130: sub start_choices {
                   1131:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   1132: 
                   1133:     if ($target ne 'helper') {
                   1134:         return '';
                   1135:     }
                   1136: 
                   1137:     # Need to initialize the choices list, so everything can assume it exists
1.24      sakharuk 1138:     $paramHash->{'variable'} = $token->[2]{'variable'} if (!defined($paramHash->{'variable'}));
1.5       bowersj2 1139:     $helper->declareVar($paramHash->{'variable'});
                   1140:     $paramHash->{'multichoice'} = $token->[2]{'multichoice'};
1.26      bowersj2 1141:     $paramHash->{'allowempty'} = $token->[2]{'allowempty'};
1.5       bowersj2 1142:     $paramHash->{CHOICES} = [];
                   1143:     return '';
                   1144: }
                   1145: 
                   1146: sub end_choices {
                   1147:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   1148: 
                   1149:     if ($target ne 'helper') {
                   1150:         return '';
                   1151:     }
                   1152:     Apache::lonhelper::choices->new();
                   1153:     return '';
                   1154: }
                   1155: 
                   1156: sub start_choice {
                   1157:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   1158: 
                   1159:     if ($target ne 'helper') {
                   1160:         return '';
                   1161:     }
                   1162: 
                   1163:     my $computer = $token->[2]{'computer'};
1.69      sakharuk 1164:     my $human = &mt(&Apache::lonxml::get_all_text('/choice',
                   1165:                                               $parser));
1.5       bowersj2 1166:     my $nextstate = $token->[2]{'nextstate'};
1.13      bowersj2 1167:     my $evalFlag = $token->[2]{'eval'};
                   1168:     push @{$paramHash->{CHOICES}}, [$human, $computer, $nextstate, 
                   1169:                                     $evalFlag];
1.5       bowersj2 1170:     return '';
                   1171: }
                   1172: 
                   1173: sub end_choice {
                   1174:     return '';
                   1175: }
                   1176: 
1.87      matthew  1177: {
                   1178:     # used to generate unique id attributes for <input> tags. 
                   1179:     # internal use only.
                   1180:     my $id = 0;
                   1181:     sub new_id { return $id++; }
                   1182: }
                   1183: 
1.5       bowersj2 1184: sub render {
                   1185:     my $self = shift;
                   1186:     my $var = $self->{'variable'};
                   1187:     my $buttons = '';
                   1188:     my $result = '';
                   1189: 
                   1190:     if ($self->{'multichoice'}) {
1.6       bowersj2 1191:         $result .= <<SCRIPT;
1.5       bowersj2 1192: <script>
1.18      bowersj2 1193:     function checkall(value, checkName) {
1.15      bowersj2 1194: 	for (i=0; i<document.forms.helpform.elements.length; i++) {
1.18      bowersj2 1195:             ele = document.forms.helpform.elements[i];
                   1196:             if (ele.name == checkName + '.forminput') {
                   1197:                 document.forms.helpform.elements[i].checked=value;
                   1198:             }
1.5       bowersj2 1199:         }
                   1200:     }
                   1201: </script>
                   1202: SCRIPT
1.25      bowersj2 1203:     }
                   1204: 
                   1205:     # Only print "select all" and "unselect all" if there are five or
                   1206:     # more choices; fewer then that and it looks silly.
                   1207:     if ($self->{'multichoice'} && scalar(@{$self->{CHOICES}}) > 4) {
1.68      sakharuk 1208:         my %lt=&Apache::lonlocal::texthash(
                   1209: 			'sa'  => "Select All",
                   1210: 		        'ua'  => "Unselect All");
1.5       bowersj2 1211:         $buttons = <<BUTTONS;
                   1212: <br />
1.68      sakharuk 1213: <input type="button" onclick="checkall(true, '$var')" value="$lt{'sa'}" />
                   1214: <input type="button" onclick="checkall(false, '$var')" value="$lt{'ua'}" />
1.6       bowersj2 1215: <br />&nbsp;
1.5       bowersj2 1216: BUTTONS
                   1217:     }
                   1218: 
1.16      bowersj2 1219:     if (defined $self->{ERROR_MSG}) {
1.6       bowersj2 1220:         $result .= '<br /><font color="#FF0000">' . $self->{ERROR_MSG} . '</font><br />';
1.5       bowersj2 1221:     }
                   1222: 
                   1223:     $result .= $buttons;
1.6       bowersj2 1224:     
1.5       bowersj2 1225:     $result .= "<table>\n\n";
                   1226: 
1.25      bowersj2 1227:     my %checkedChoices;
                   1228:     my $checkedChoicesFunc;
                   1229: 
                   1230:     if (defined($self->{DEFAULT_VALUE})) {
                   1231:         $checkedChoicesFunc = eval ($self->{DEFAULT_VALUE});
                   1232:         die 'Error in default value code for variable ' . 
1.34      bowersj2 1233:             $self->{'variable'} . ', Perl said: ' . $@ if $@;
1.25      bowersj2 1234:     } else {
                   1235:         $checkedChoicesFunc = sub { return ''; };
                   1236:     }
                   1237: 
                   1238:     # Process which choices should be checked.
                   1239:     if ($self->{'multichoice'}) {
                   1240:         for my $selectedChoice (split(/\|\|\|/, (&$checkedChoicesFunc($helper, $self)))) {
                   1241:             $checkedChoices{$selectedChoice} = 1;
                   1242:         }
                   1243:     } else {
                   1244:         # single choice
                   1245:         my $selectedChoice = &$checkedChoicesFunc($helper, $self);
                   1246:         
                   1247:         my $foundChoice = 0;
                   1248:         
                   1249:         # check that the choice is in the list of choices.
                   1250:         for my $choice (@{$self->{CHOICES}}) {
                   1251:             if ($choice->[1] eq $selectedChoice) {
                   1252:                 $checkedChoices{$choice->[1]} = 1;
                   1253:                 $foundChoice = 1;
                   1254:             }
                   1255:         }
                   1256:         
                   1257:         # If we couldn't find the choice, pick the first one 
                   1258:         if (!$foundChoice) {
                   1259:             $checkedChoices{$self->{CHOICES}->[0]->[1]} = 1;
                   1260:         }
                   1261:     }
                   1262: 
1.5       bowersj2 1263:     my $type = "radio";
                   1264:     if ($self->{'multichoice'}) { $type = 'checkbox'; }
                   1265:     foreach my $choice (@{$self->{CHOICES}}) {
1.87      matthew  1266:         my $id = &new_id();
1.5       bowersj2 1267:         $result .= "<tr>\n<td width='20'>&nbsp;</td>\n";
                   1268:         $result .= "<td valign='top'><input type='$type' name='$var.forminput'"
                   1269:             . "' value='" . 
1.89      foxr     1270:             HTML::Entities::encode($choice->[1],"<>&\"'") 
1.5       bowersj2 1271:             . "'";
1.25      bowersj2 1272:         if ($checkedChoices{$choice->[1]}) {
1.5       bowersj2 1273:             $result .= " checked ";
                   1274:         }
1.87      matthew  1275:         $result .= qq{id="$id"};
1.13      bowersj2 1276:         my $choiceLabel = $choice->[0];
                   1277:         if ($choice->[4]) {  # if we need to evaluate this choice
                   1278:             $choiceLabel = "sub { my $helper = shift; my $state = shift;" .
                   1279:                 $choiceLabel . "}";
                   1280:             $choiceLabel = eval($choiceLabel);
                   1281:             $choiceLabel = &$choiceLabel($helper, $self);
                   1282:         }
1.87      matthew  1283:         $result .= "/></td><td> ".qq{<label for="$id">}.
                   1284:             &mtn($choiceLabel). "</label></td></tr>\n";
1.5       bowersj2 1285:     }
                   1286:     $result .= "</table>\n\n\n";
                   1287:     $result .= $buttons;
                   1288: 
                   1289:     return $result;
                   1290: }
                   1291: 
                   1292: # If a NEXTSTATE was given or a nextstate for this choice was
                   1293: # given, switch to it
                   1294: sub postprocess {
                   1295:     my $self = shift;
                   1296:     my $chosenValue = $ENV{'form.' . $self->{'variable'} . '.forminput'};
                   1297: 
1.26      bowersj2 1298:     if (!defined($chosenValue) && !$self->{'allowempty'}) {
1.59      bowersj2 1299:         $self->{ERROR_MSG} = 
                   1300: 	    &mt("You must choose one or more choices to continue.");
1.6       bowersj2 1301:         return 0;
                   1302:     }
                   1303: 
1.28      bowersj2 1304:     if (ref($chosenValue)) {
                   1305:         $helper->{VARS}->{$self->{'variable'}} = join('|||', @$chosenValue);
1.42      bowersj2 1306:     }
                   1307: 
                   1308:     if (defined($self->{NEXTSTATE})) {
                   1309:         $helper->changeState($self->{NEXTSTATE});
                   1310:     }
                   1311:     
                   1312:     foreach my $choice (@{$self->{CHOICES}}) {
                   1313:         if ($choice->[1] eq $chosenValue) {
                   1314:             if (defined($choice->[2])) {
                   1315:                 $helper->changeState($choice->[2]);
                   1316:             }
                   1317:         }
                   1318:     }
                   1319:     return 1;
                   1320: }
                   1321: 1;
                   1322: 
                   1323: package Apache::lonhelper::dropdown;
                   1324: 
                   1325: =pod
                   1326: 
1.44      bowersj2 1327: =head2 Element: dropdownX<dropdown, helper tag>
1.42      bowersj2 1328: 
                   1329: A drop-down provides a drop-down box instead of a radio button
                   1330: box. Because most people do not know how to use a multi-select
                   1331: drop-down box, that option is not allowed. Otherwise, the arguments
                   1332: are the same as "choices", except "allowempty" is also meaningless.
                   1333: 
                   1334: <dropdown> takes an attribute "variable" to control which helper variable
                   1335: the result is stored in.
                   1336: 
1.44      bowersj2 1337: =head3 SUB-TAGS
1.42      bowersj2 1338: 
                   1339: <choice>, which acts just as it does in the "choices" element.
                   1340: 
                   1341: =cut
                   1342: 
1.57      albertel 1343: # This really ought to be a sibling class to "choice" which is itself
                   1344: # a child of some abstract class.... *shrug*
                   1345: 
1.42      bowersj2 1346: no strict;
                   1347: @ISA = ("Apache::lonhelper::element");
                   1348: use strict;
1.57      albertel 1349: use Apache::lonlocal;
1.42      bowersj2 1350: 
                   1351: BEGIN {
                   1352:     &Apache::lonhelper::register('Apache::lonhelper::dropdown',
                   1353:                               ('dropdown'));
                   1354: }
                   1355: 
                   1356: sub new {
                   1357:     my $ref = Apache::lonhelper::element->new();
                   1358:     bless($ref);
                   1359: }
                   1360: 
                   1361: # CONSTRUCTION: Construct the message element from the XML
                   1362: sub start_dropdown {
                   1363:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   1364: 
                   1365:     if ($target ne 'helper') {
                   1366:         return '';
                   1367:     }
                   1368: 
                   1369:     # Need to initialize the choices list, so everything can assume it exists
                   1370:     $paramHash->{'variable'} = $token->[2]{'variable'} if (!defined($paramHash->{'variable'}));
                   1371:     $helper->declareVar($paramHash->{'variable'});
                   1372:     $paramHash->{CHOICES} = [];
                   1373:     return '';
                   1374: }
                   1375: 
                   1376: sub end_dropdown {
                   1377:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   1378: 
                   1379:     if ($target ne 'helper') {
                   1380:         return '';
                   1381:     }
                   1382:     Apache::lonhelper::dropdown->new();
                   1383:     return '';
                   1384: }
                   1385: 
                   1386: sub render {
                   1387:     my $self = shift;
                   1388:     my $var = $self->{'variable'};
                   1389:     my $result = '';
                   1390: 
                   1391:     if (defined $self->{ERROR_MSG}) {
                   1392:         $result .= '<br /><font color="#FF0000">' . $self->{ERROR_MSG} . '</font><br />';
                   1393:     }
                   1394: 
                   1395:     my %checkedChoices;
                   1396:     my $checkedChoicesFunc;
                   1397: 
                   1398:     if (defined($self->{DEFAULT_VALUE})) {
                   1399:         $checkedChoicesFunc = eval ($self->{DEFAULT_VALUE});
                   1400:         die 'Error in default value code for variable ' . 
                   1401:             $self->{'variable'} . ', Perl said: ' . $@ if $@;
                   1402:     } else {
                   1403:         $checkedChoicesFunc = sub { return ''; };
                   1404:     }
                   1405: 
                   1406:     # single choice
                   1407:     my $selectedChoice = &$checkedChoicesFunc($helper, $self);
                   1408:     
                   1409:     my $foundChoice = 0;
                   1410:     
                   1411:     # check that the choice is in the list of choices.
                   1412:     for my $choice (@{$self->{CHOICES}}) {
                   1413: 	if ($choice->[1] eq $selectedChoice) {
                   1414: 	    $checkedChoices{$choice->[1]} = 1;
                   1415: 	    $foundChoice = 1;
                   1416: 	}
                   1417:     }
                   1418:     
                   1419:     # If we couldn't find the choice, pick the first one 
                   1420:     if (!$foundChoice) {
                   1421: 	$checkedChoices{$self->{CHOICES}->[0]->[1]} = 1;
                   1422:     }
                   1423: 
                   1424:     $result .= "<select name='${var}.forminput'>\n";
                   1425:     foreach my $choice (@{$self->{CHOICES}}) {
                   1426:         $result .= "<option value='" . 
1.89      foxr     1427:             HTML::Entities::encode($choice->[1],"<>&\"'") 
1.42      bowersj2 1428:             . "'";
                   1429:         if ($checkedChoices{$choice->[1]}) {
                   1430:             $result .= " selected";
                   1431:         }
                   1432:         my $choiceLabel = $choice->[0];
                   1433:         if ($choice->[4]) {  # if we need to evaluate this choice
                   1434:             $choiceLabel = "sub { my $helper = shift; my $state = shift;" .
                   1435:                 $choiceLabel . "}";
                   1436:             $choiceLabel = eval($choiceLabel);
                   1437:             $choiceLabel = &$choiceLabel($helper, $self);
                   1438:         }
1.57      albertel 1439:         $result .= ">" . &mtn($choiceLabel) . "\n";
1.42      bowersj2 1440:     }
1.43      bowersj2 1441:     $result .= "</select>\n";
1.42      bowersj2 1442: 
                   1443:     return $result;
                   1444: }
                   1445: 
                   1446: # If a NEXTSTATE was given or a nextstate for this choice was
                   1447: # given, switch to it
                   1448: sub postprocess {
                   1449:     my $self = shift;
                   1450:     my $chosenValue = $ENV{'form.' . $self->{'variable'} . '.forminput'};
                   1451: 
                   1452:     if (!defined($chosenValue) && !$self->{'allowempty'}) {
                   1453:         $self->{ERROR_MSG} = "You must choose one or more choices to" .
                   1454:             " continue.";
                   1455:         return 0;
1.6       bowersj2 1456:     }
                   1457: 
1.5       bowersj2 1458:     if (defined($self->{NEXTSTATE})) {
                   1459:         $helper->changeState($self->{NEXTSTATE});
                   1460:     }
                   1461:     
                   1462:     foreach my $choice (@{$self->{CHOICES}}) {
                   1463:         if ($choice->[1] eq $chosenValue) {
                   1464:             if (defined($choice->[2])) {
                   1465:                 $helper->changeState($choice->[2]);
                   1466:             }
                   1467:         }
                   1468:     }
1.6       bowersj2 1469:     return 1;
1.5       bowersj2 1470: }
                   1471: 1;
                   1472: 
                   1473: package Apache::lonhelper::date;
                   1474: 
                   1475: =pod
                   1476: 
1.44      bowersj2 1477: =head2 Element: dateX<date, helper element>
1.5       bowersj2 1478: 
                   1479: Date elements allow the selection of a date with a drop down list.
                   1480: 
                   1481: Date elements can take two attributes:
                   1482: 
                   1483: =over 4
                   1484: 
                   1485: =item * B<variable>: The name of the variable to store the chosen
                   1486:         date in. Required.
                   1487: 
                   1488: =item * B<hoursminutes>: If a true value, the date will show hours
                   1489:         and minutes, as well as month/day/year. If false or missing,
                   1490:         the date will only show the month, day, and year.
                   1491: 
                   1492: =back
                   1493: 
                   1494: Date elements contain only an option <nextstate> tag to determine
                   1495: the next state.
                   1496: 
                   1497: Example:
                   1498: 
                   1499:  <date variable="DUE_DATE" hoursminutes="1">
                   1500:    <nextstate>choose_why</nextstate>
                   1501:    </date>
                   1502: 
                   1503: =cut
                   1504: 
                   1505: no strict;
                   1506: @ISA = ("Apache::lonhelper::element");
                   1507: use strict;
1.57      albertel 1508: use Apache::lonlocal; # A localization nightmare
1.5       bowersj2 1509: 
                   1510: use Time::localtime;
                   1511: 
                   1512: BEGIN {
1.7       bowersj2 1513:     &Apache::lonhelper::register('Apache::lonhelper::date',
1.5       bowersj2 1514:                               ('date'));
                   1515: }
                   1516: 
                   1517: # Don't need to override the "new" from element
                   1518: sub new {
                   1519:     my $ref = Apache::lonhelper::element->new();
                   1520:     bless($ref);
                   1521: }
                   1522: 
                   1523: my @months = ("January", "February", "March", "April", "May", "June", "July",
                   1524: 	      "August", "September", "October", "November", "December");
                   1525: 
                   1526: # CONSTRUCTION: Construct the message element from the XML
                   1527: sub start_date {
                   1528:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   1529: 
                   1530:     if ($target ne 'helper') {
                   1531:         return '';
                   1532:     }
                   1533: 
                   1534:     $paramHash->{'variable'} = $token->[2]{'variable'};
                   1535:     $helper->declareVar($paramHash->{'variable'});
                   1536:     $paramHash->{'hoursminutes'} = $token->[2]{'hoursminutes'};
                   1537: }
                   1538: 
                   1539: sub end_date {
                   1540:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   1541: 
                   1542:     if ($target ne 'helper') {
                   1543:         return '';
                   1544:     }
                   1545:     Apache::lonhelper::date->new();
                   1546:     return '';
                   1547: }
                   1548: 
                   1549: sub render {
                   1550:     my $self = shift;
                   1551:     my $result = "";
                   1552:     my $var = $self->{'variable'};
                   1553: 
                   1554:     my $date;
                   1555:     
                   1556:     # Default date: The current hour.
                   1557:     $date = localtime();
                   1558:     $date->min(0);
                   1559: 
                   1560:     if (defined $self->{ERROR_MSG}) {
                   1561:         $result .= '<font color="#FF0000">' . $self->{ERROR_MSG} . '</font><br /><br />';
                   1562:     }
                   1563: 
                   1564:     # Month
                   1565:     my $i;
                   1566:     $result .= "<select name='${var}month'>\n";
                   1567:     for ($i = 0; $i < 12; $i++) {
                   1568:         if ($i == $date->mon) {
                   1569:             $result .= "<option value='$i' selected>";
                   1570:         } else {
                   1571:             $result .= "<option value='$i'>";
                   1572:         }
1.57      albertel 1573:         $result .= &mt($months[$i]) . "</option>\n";
1.5       bowersj2 1574:     }
                   1575:     $result .= "</select>\n";
                   1576: 
                   1577:     # Day
                   1578:     $result .= "<select name='${var}day'>\n";
                   1579:     for ($i = 1; $i < 32; $i++) {
                   1580:         if ($i == $date->mday) {
                   1581:             $result .= '<option selected>';
                   1582:         } else {
                   1583:             $result .= '<option>';
                   1584:         }
                   1585:         $result .= "$i</option>\n";
                   1586:     }
                   1587:     $result .= "</select>,\n";
                   1588: 
                   1589:     # Year
                   1590:     $result .= "<select name='${var}year'>\n";
                   1591:     for ($i = 2000; $i < 2030; $i++) { # update this after 64-bit dates
                   1592:         if ($date->year + 1900 == $i) {
                   1593:             $result .= "<option selected>";
                   1594:         } else {
                   1595:             $result .= "<option>";
                   1596:         }
                   1597:         $result .= "$i</option>\n";
                   1598:     }
                   1599:     $result .= "</select>,\n";
                   1600: 
                   1601:     # Display Hours and Minutes if they are called for
                   1602:     if ($self->{'hoursminutes'}) {
1.59      bowersj2 1603: 	# This needs parameterization for times.
                   1604: 	my $am = &mt('a.m.');
                   1605: 	my $pm = &mt('p.m.');
1.5       bowersj2 1606:         # Build hour
                   1607:         $result .= "<select name='${var}hour'>\n";
                   1608:         $result .= "<option " . ($date->hour == 0 ? 'selected ':'') .
1.59      bowersj2 1609:             " value='0'>" . &mt('midnight') . "</option>\n";
1.5       bowersj2 1610:         for ($i = 1; $i < 12; $i++) {
                   1611:             if ($date->hour == $i) {
1.59      bowersj2 1612:                 $result .= "<option selected value='$i'>$i $am</option>\n";
1.5       bowersj2 1613:             } else {
1.59      bowersj2 1614:                 $result .= "<option value='$i'>$i $am</option>\n";
1.5       bowersj2 1615:             }
                   1616:         }
                   1617:         $result .= "<option " . ($date->hour == 12 ? 'selected ':'') .
1.59      bowersj2 1618:             " value='12'>" . &mt('noon') . "</option>\n";
1.5       bowersj2 1619:         for ($i = 13; $i < 24; $i++) {
                   1620:             my $printedHour = $i - 12;
                   1621:             if ($date->hour == $i) {
1.59      bowersj2 1622:                 $result .= "<option selected value='$i'>$printedHour $pm</option>\n";
1.5       bowersj2 1623:             } else {
1.59      bowersj2 1624:                 $result .= "<option value='$i'>$printedHour $pm</option>\n";
1.5       bowersj2 1625:             }
                   1626:         }
                   1627: 
                   1628:         $result .= "</select> :\n";
                   1629: 
                   1630:         $result .= "<select name='${var}minute'>\n";
                   1631:         for ($i = 0; $i < 60; $i++) {
                   1632:             my $printedMinute = $i;
                   1633:             if ($i < 10) {
                   1634:                 $printedMinute = "0" . $printedMinute;
                   1635:             }
                   1636:             if ($date->min == $i) {
                   1637:                 $result .= "<option selected>";
                   1638:             } else {
                   1639:                 $result .= "<option>";
                   1640:             }
                   1641:             $result .= "$printedMinute</option>\n";
                   1642:         }
                   1643:         $result .= "</select>\n";
                   1644:     }
                   1645: 
                   1646:     return $result;
                   1647: 
                   1648: }
                   1649: # If a NEXTSTATE was given, switch to it
                   1650: sub postprocess {
                   1651:     my $self = shift;
                   1652:     my $var = $self->{'variable'};
                   1653:     my $month = $ENV{'form.' . $var . 'month'}; 
                   1654:     my $day = $ENV{'form.' . $var . 'day'}; 
                   1655:     my $year = $ENV{'form.' . $var . 'year'}; 
                   1656:     my $min = 0; 
                   1657:     my $hour = 0;
                   1658:     if ($self->{'hoursminutes'}) {
                   1659:         $min = $ENV{'form.' . $var . 'minute'};
                   1660:         $hour = $ENV{'form.' . $var . 'hour'};
                   1661:     }
                   1662: 
1.57      albertel 1663:     my $chosenDate;
                   1664:     eval {$chosenDate = Time::Local::timelocal(0, $min, $hour, $day, $month, $year);};
                   1665:     my $error = $@;
                   1666: 
1.5       bowersj2 1667:     # Check to make sure that the date was not automatically co-erced into a 
                   1668:     # valid date, as we want to flag that as an error
                   1669:     # This happens for "Feb. 31", for instance, which is coerced to March 2 or
1.57      albertel 1670:     # 3, depending on if it's a leap year
1.5       bowersj2 1671:     my $checkDate = localtime($chosenDate);
                   1672: 
1.57      albertel 1673:     if ($error || $checkDate->mon != $month || $checkDate->mday != $day ||
1.5       bowersj2 1674:         $checkDate->year + 1900 != $year) {
1.57      albertel 1675: 	unless (Apache::lonlocal::current_language()== ~/^en/) {
                   1676: 	    $self->{ERROR_MSG} = &mt("Invalid date entry");
                   1677: 	    return 0;
                   1678: 	}
                   1679: 	# LOCALIZATION FIXME: Needs to be parameterized
1.5       bowersj2 1680:         $self->{ERROR_MSG} = "Can't use " . $months[$month] . " $day, $year as a "
                   1681:             . "date because it doesn't exist. Please enter a valid date.";
1.57      albertel 1682: 
1.6       bowersj2 1683:         return 0;
1.5       bowersj2 1684:     }
                   1685: 
                   1686:     $helper->{VARS}->{$var} = $chosenDate;
                   1687: 
                   1688:     if (defined($self->{NEXTSTATE})) {
                   1689:         $helper->changeState($self->{NEXTSTATE});
                   1690:     }
1.6       bowersj2 1691: 
                   1692:     return 1;
1.5       bowersj2 1693: }
                   1694: 1;
                   1695: 
                   1696: package Apache::lonhelper::resource;
                   1697: 
                   1698: =pod
                   1699: 
1.44      bowersj2 1700: =head2 Element: resourceX<resource, helper element>
1.5       bowersj2 1701: 
                   1702: <resource> elements allow the user to select one or multiple resources
                   1703: from the current course. You can filter out which resources they can view,
                   1704: and filter out which resources they can select. The course will always
                   1705: be displayed fully expanded, because of the difficulty of maintaining
                   1706: selections across folder openings and closings. If this is fixed, then
                   1707: the user can manipulate the folders.
                   1708: 
                   1709: <resource> takes the standard variable attribute to control what helper
1.44      bowersj2 1710: variable stores the results. It also takes a "multichoice"X<multichoice> attribute,
1.17      bowersj2 1711: which controls whether the user can select more then one resource. The 
                   1712: "toponly" attribute controls whether the resource display shows just the
                   1713: resources in that sequence, or recurses into all sub-sequences, defaulting
1.29      bowersj2 1714: to false. The "suppressEmptySequences" attribute reflects the 
                   1715: suppressEmptySequences argument to the render routine, which will cause
                   1716: folders that have all of their contained resources filtered out to also
1.46      bowersj2 1717: be filtered out. The 'addstatus' attribute, if true, will add the icon
                   1718: and long status display columns to the display.
1.5       bowersj2 1719: 
1.44      bowersj2 1720: =head3 SUB-TAGS
1.5       bowersj2 1721: 
                   1722: =over 4
                   1723: 
1.44      bowersj2 1724: =item * <filterfunc>X<filterfunc>: If you want to filter what resources are displayed
1.5       bowersj2 1725:   to the user, use a filter func. The <filterfunc> tag should contain
                   1726:   Perl code that when wrapped with "sub { my $res = shift; " and "}" is 
                   1727:   a function that returns true if the resource should be displayed, 
                   1728:   and false if it should be skipped. $res is a resource object. 
                   1729:   (See Apache::lonnavmaps documentation for information about the 
                   1730:   resource object.)
                   1731: 
1.44      bowersj2 1732: =item * <choicefunc>X<choicefunc>: Same as <filterfunc>, except that controls whether
1.5       bowersj2 1733:   the given resource can be chosen. (It is almost always a good idea to
                   1734:   show the user the folders, for instance, but you do not always want to 
                   1735:   let the user select them.)
                   1736: 
                   1737: =item * <nextstate>: Standard nextstate behavior.
                   1738: 
1.44      bowersj2 1739: =item * <valuefunc>X<valuefunc>: This function controls what is returned by the resource
1.5       bowersj2 1740:   when the user selects it. Like filterfunc and choicefunc, it should be
                   1741:   a function fragment that when wrapped by "sub { my $res = shift; " and
                   1742:   "}" returns a string representing what you want to have as the value. By
                   1743:   default, the value will be the resource ID of the object ($res->{ID}).
                   1744: 
1.44      bowersj2 1745: =item * <mapurl>X<mapurl>: If the URL of a map is given here, only that map
1.48      bowersj2 1746:   will be displayed, instead of the whole course. If the attribute
                   1747:   "evaluate" is given and is true, the contents of the mapurl will be
                   1748:   evaluated with "sub { my $helper = shift; my $state = shift;" and
                   1749:   "}", with the return value used as the mapurl.
1.13      bowersj2 1750: 
1.5       bowersj2 1751: =back
                   1752: 
                   1753: =cut
                   1754: 
                   1755: no strict;
                   1756: @ISA = ("Apache::lonhelper::element");
                   1757: use strict;
                   1758: 
                   1759: BEGIN {
1.7       bowersj2 1760:     &Apache::lonhelper::register('Apache::lonhelper::resource',
1.5       bowersj2 1761:                               ('resource', 'filterfunc', 
1.13      bowersj2 1762:                                'choicefunc', 'valuefunc',
1.90      foxr     1763:                                'mapurl','option'));
1.5       bowersj2 1764: }
                   1765: 
                   1766: sub new {
                   1767:     my $ref = Apache::lonhelper::element->new();
                   1768:     bless($ref);
                   1769: }
                   1770: 
                   1771: # CONSTRUCTION: Construct the message element from the XML
                   1772: sub start_resource {
                   1773:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   1774: 
                   1775:     if ($target ne 'helper') {
                   1776:         return '';
                   1777:     }
                   1778: 
                   1779:     $paramHash->{'variable'} = $token->[2]{'variable'};
                   1780:     $helper->declareVar($paramHash->{'variable'});
1.14      bowersj2 1781:     $paramHash->{'multichoice'} = $token->[2]{'multichoice'};
1.29      bowersj2 1782:     $paramHash->{'suppressEmptySequences'} = $token->[2]{'suppressEmptySequences'};
1.17      bowersj2 1783:     $paramHash->{'toponly'} = $token->[2]{'toponly'};
1.46      bowersj2 1784:     $paramHash->{'addstatus'} = $token->[2]{'addstatus'};
1.66      albertel 1785:     $paramHash->{'closeallpages'} = $token->[2]{'closeallpages'};
1.5       bowersj2 1786:     return '';
                   1787: }
                   1788: 
                   1789: sub end_resource {
                   1790:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   1791: 
                   1792:     if ($target ne 'helper') {
                   1793:         return '';
                   1794:     }
                   1795:     if (!defined($paramHash->{FILTER_FUNC})) {
                   1796:         $paramHash->{FILTER_FUNC} = sub {return 1;};
                   1797:     }
                   1798:     if (!defined($paramHash->{CHOICE_FUNC})) {
                   1799:         $paramHash->{CHOICE_FUNC} = sub {return 1;};
                   1800:     }
                   1801:     if (!defined($paramHash->{VALUE_FUNC})) {
                   1802:         $paramHash->{VALUE_FUNC} = sub {my $res = shift; return $res->{ID}; };
                   1803:     }
                   1804:     Apache::lonhelper::resource->new();
1.4       bowersj2 1805:     return '';
                   1806: }
                   1807: 
1.5       bowersj2 1808: sub start_filterfunc {
                   1809:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   1810: 
                   1811:     if ($target ne 'helper') {
                   1812:         return '';
                   1813:     }
                   1814: 
                   1815:     my $contents = Apache::lonxml::get_all_text('/filterfunc',
                   1816:                                                 $parser);
                   1817:     $contents = 'sub { my $res = shift; ' . $contents . '}';
                   1818:     $paramHash->{FILTER_FUNC} = eval $contents;
                   1819: }
                   1820: 
                   1821: sub end_filterfunc { return ''; }
                   1822: 
                   1823: sub start_choicefunc {
                   1824:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   1825: 
                   1826:     if ($target ne 'helper') {
                   1827:         return '';
                   1828:     }
                   1829: 
                   1830:     my $contents = Apache::lonxml::get_all_text('/choicefunc',
                   1831:                                                 $parser);
                   1832:     $contents = 'sub { my $res = shift; ' . $contents . '}';
                   1833:     $paramHash->{CHOICE_FUNC} = eval $contents;
                   1834: }
                   1835: 
                   1836: sub end_choicefunc { return ''; }
                   1837: 
                   1838: sub start_valuefunc {
                   1839:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   1840: 
                   1841:     if ($target ne 'helper') {
                   1842:         return '';
                   1843:     }
                   1844: 
                   1845:     my $contents = Apache::lonxml::get_all_text('/valuefunc',
                   1846:                                                 $parser);
                   1847:     $contents = 'sub { my $res = shift; ' . $contents . '}';
                   1848:     $paramHash->{VALUE_FUNC} = eval $contents;
                   1849: }
                   1850: 
                   1851: sub end_valuefunc { return ''; }
                   1852: 
1.13      bowersj2 1853: sub start_mapurl {
                   1854:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   1855: 
                   1856:     if ($target ne 'helper') {
                   1857:         return '';
                   1858:     }
                   1859: 
                   1860:     my $contents = Apache::lonxml::get_all_text('/mapurl',
                   1861:                                                 $parser);
1.48      bowersj2 1862:     $paramHash->{EVAL_MAP_URL} = $token->[2]{'evaluate'};
1.14      bowersj2 1863:     $paramHash->{MAP_URL} = $contents;
1.13      bowersj2 1864: }
                   1865: 
                   1866: sub end_mapurl { return ''; }
                   1867: 
1.90      foxr     1868: 
                   1869: sub start_option {
                   1870:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   1871:     if (!defined($paramHash->{OPTION_TEXTS})) {
                   1872: 	$paramHash->{OPTION_TEXTS} = [ ];
                   1873: 	$paramHash->{OPTION_VARS}  = [ ];
1.91      foxr     1874: 
1.90      foxr     1875:     }
1.91      foxr     1876:     # OPTION_TEXTS is a list of the text attribute
                   1877:     #               values used to create column headings.
                   1878:     # OPTION_VARS is a list of the variable names, used to create the checkbox
                   1879:     #             inputs.
1.90      foxr     1880:     #  We're ok with empty elements. as place holders
                   1881:     # Although the 'variable' element should really exist.
1.91      foxr     1882:     #
                   1883: 
1.90      foxr     1884:     my $option_texts  = $paramHash->{OPTION_TEXTS};
                   1885:     my $option_vars   = $paramHash->{OPTION_VARS};
                   1886:     push(@$option_texts,  $token->[2]{'text'});
                   1887:     push(@$option_vars,   $token->[2]{'variable'});
                   1888: 
1.91      foxr     1889:     #  Need to create and declare the option variables as well to make them
                   1890:     # persistent.
                   1891:     #
                   1892:     my $varname = $token->[2]{'variable'};
                   1893:     $helper->declareVar($varname);
                   1894: 
                   1895: 
1.90      foxr     1896:     return '';
                   1897: }
                   1898: 
                   1899: sub end_option {
                   1900:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   1901:     return '';
                   1902: }
                   1903: 
1.5       bowersj2 1904: # A note, in case I don't get to this before I leave.
                   1905: # If someone complains about the "Back" button returning them
                   1906: # to the previous folder state, instead of returning them to
                   1907: # the previous helper state, the *correct* answer is for the helper
                   1908: # to keep track of how many times the user has manipulated the folders,
                   1909: # and feed that to the history.go() call in the helper rendering routines.
                   1910: # If done correctly, the helper itself can keep track of how many times
                   1911: # it renders the same states, so it doesn't go in just this state, and
                   1912: # you can lean on the browser back button to make sure it all chains
                   1913: # correctly.
                   1914: # Right now, though, I'm just forcing all folders open.
                   1915: 
                   1916: sub render {
                   1917:     my $self = shift;
                   1918:     my $result = "";
                   1919:     my $var = $self->{'variable'};
                   1920:     my $curVal = $helper->{VARS}->{$var};
                   1921: 
1.15      bowersj2 1922:     my $buttons = '';
                   1923: 
                   1924:     if ($self->{'multichoice'}) {
                   1925:         $result = <<SCRIPT;
                   1926: <script>
1.18      bowersj2 1927:     function checkall(value, checkName) {
1.15      bowersj2 1928: 	for (i=0; i<document.forms.helpform.elements.length; i++) {
                   1929:             ele = document.forms.helpform.elements[i];
1.18      bowersj2 1930:             if (ele.name == checkName + '.forminput') {
1.15      bowersj2 1931:                 document.forms.helpform.elements[i].checked=value;
                   1932:             }
                   1933:         }
                   1934:     }
                   1935: </script>
                   1936: SCRIPT
1.68      sakharuk 1937:         my %lt=&Apache::lonlocal::texthash(
                   1938: 			'sar'  => "Select All Resources",
                   1939: 		        'uar'  => "Unselect All Resources");
                   1940: 
1.15      bowersj2 1941:         $buttons = <<BUTTONS;
                   1942: <br /> &nbsp;
1.68      sakharuk 1943: <input type="button" onclick="checkall(true, '$var')" value="$lt{'sar'}" />
                   1944: <input type="button" onclick="checkall(false, '$var')" value="$lt{'uar'}" />
1.15      bowersj2 1945: <br /> &nbsp;
                   1946: BUTTONS
                   1947:     }
                   1948: 
1.5       bowersj2 1949:     if (defined $self->{ERROR_MSG}) {
1.14      bowersj2 1950:         $result .= '<br /><font color="#FF0000">' . $self->{ERROR_MSG} . '</font><br /><br />';
1.5       bowersj2 1951:     }
                   1952: 
1.15      bowersj2 1953:     $result .= $buttons;
                   1954: 
1.90      foxr     1955:     my $filterFunc     = $self->{FILTER_FUNC};
                   1956:     my $choiceFunc     = $self->{CHOICE_FUNC};
                   1957:     my $valueFunc      = $self->{VALUE_FUNC};
                   1958:     my $multichoice   = $self->{'multichoice'};
                   1959:     my $option_vars    = $self->{OPTION_VARS};
                   1960:     my $option_texts   = $self->{OPTION_TEXTS};
                   1961:     my $headings_done  = 0;
1.5       bowersj2 1962: 
1.48      bowersj2 1963:     # Evaluate the map url as needed
                   1964:     my $mapUrl;
1.49      bowersj2 1965:     if ($self->{EVAL_MAP_URL}) {
1.48      bowersj2 1966: 	my $mapUrlFunc = eval('sub { my $helper = shift; my $state = shift; ' . 
                   1967: 	    $self->{MAP_URL} . '}');
                   1968: 	$mapUrl = &$mapUrlFunc($helper, $self);
                   1969:     } else {
                   1970: 	$mapUrl = $self->{MAP_URL};
                   1971:     }
                   1972: 
1.5       bowersj2 1973:     # Create the composite function that renders the column on the nav map
                   1974:     # have to admit any language that lets me do this can't be all bad
                   1975:     #  - Jeremy (Pythonista) ;-)
                   1976:     my $checked = 0;
                   1977:     my $renderColFunc = sub {
                   1978:         my ($resource, $part, $params) = @_;
1.90      foxr     1979: 	my $result = "";
                   1980: 
                   1981: 	if(!$headings_done) {
                   1982: 	    if ($option_texts) {
                   1983: 		foreach my $text (@$option_texts) {
                   1984: 		    $result .= "<th>$text</th>";
                   1985: 		}
                   1986: 	    }
                   1987: 	    $result .= "<th>Select</th>";
                   1988: 	    $result .= "</tr><tr>"; # Close off the extra row and start a new one.
                   1989: 	    $headings_done = 1;
                   1990: 	}
1.14      bowersj2 1991: 
                   1992:         my $inputType;
                   1993:         if ($multichoice) { $inputType = 'checkbox'; }
                   1994:         else {$inputType = 'radio'; }
                   1995: 
1.5       bowersj2 1996:         if (!&$choiceFunc($resource)) {
1.90      foxr     1997: 	    $result .= '<td>&nbsp;</td>';
                   1998:             return $result;
1.5       bowersj2 1999:         } else {
1.90      foxr     2000: 	    my $col = "";
                   2001: 	    my $resource_name =   
                   2002:                    HTML::Entities::encode(&$valueFunc($resource),"<>&\"'");
                   2003: 	    if($option_vars) {
1.91      foxr     2004: 		foreach my $option_var (@$option_vars) {
1.90      foxr     2005: 		    $col .= 
1.91      foxr     2006:                         "<td align='center'><input type='checkbox' name ='$option_var".
                   2007: 			".forminput' value='".
1.90      foxr     2008: 			$resource_name . "' /> </td>";
                   2009: 		}
                   2010: 	    }
                   2011: 
                   2012:             $col .= "<td align='center'><input type='$inputType' name='${var}.forminput' ";
1.14      bowersj2 2013:             if (!$checked && !$multichoice) {
1.5       bowersj2 2014:                 $col .= "checked ";
                   2015:                 $checked = 1;
                   2016:             }
1.37      bowersj2 2017: 	    if ($multichoice) { # all resources start checked; see bug 1174
                   2018: 		$col .= "checked ";
                   2019: 		$checked = 1;
                   2020: 	    }
1.90      foxr     2021:             $col .= "value='" . $resource_name  . "' /></td>";
                   2022:             return $result.$col;
1.5       bowersj2 2023:         }
                   2024:     };
                   2025: 
1.17      bowersj2 2026:     $ENV{'form.condition'} = !$self->{'toponly'};
1.46      bowersj2 2027:     my $cols = [$renderColFunc, Apache::lonnavmaps::resource()];
                   2028:     if ($self->{'addstatus'}) {
                   2029: 	push @$cols, (Apache::lonnavmaps::part_status_summary());
                   2030: 	
                   2031:     }
1.5       bowersj2 2032:     $result .= 
1.46      bowersj2 2033:         &Apache::lonnavmaps::render( { 'cols' => $cols,
1.5       bowersj2 2034:                                        'showParts' => 0,
                   2035:                                        'filterFunc' => $filterFunc,
1.13      bowersj2 2036:                                        'resource_no_folder_link' => 1,
1.66      albertel 2037: 				       'closeAllPages' => $self->{'closeallpages'},
1.29      bowersj2 2038:                                        'suppressEmptySequences' => $self->{'suppressEmptySequences'},
1.13      bowersj2 2039:                                        'iterator_map' => $mapUrl }
1.5       bowersj2 2040:                                        );
1.15      bowersj2 2041: 
                   2042:     $result .= $buttons;
1.5       bowersj2 2043:                                                 
                   2044:     return $result;
                   2045: }
                   2046:     
                   2047: sub postprocess {
                   2048:     my $self = shift;
1.14      bowersj2 2049: 
                   2050:     if ($self->{'multichoice'} && !$helper->{VARS}->{$self->{'variable'}}) {
                   2051:         $self->{ERROR_MSG} = 'You must choose at least one resource to continue.';
                   2052:         return 0;
                   2053:     }
                   2054: 
1.5       bowersj2 2055:     if (defined($self->{NEXTSTATE})) {
                   2056:         $helper->changeState($self->{NEXTSTATE});
                   2057:     }
1.6       bowersj2 2058: 
                   2059:     return 1;
1.5       bowersj2 2060: }
                   2061: 
                   2062: 1;
                   2063: 
                   2064: package Apache::lonhelper::student;
                   2065: 
                   2066: =pod
                   2067: 
1.44      bowersj2 2068: =head2 Element: studentX<student, helper element>
1.5       bowersj2 2069: 
                   2070: Student elements display a choice of students enrolled in the current
                   2071: course. Currently it is primitive; this is expected to evolve later.
                   2072: 
1.48      bowersj2 2073: Student elements take the following attributes: 
                   2074: 
                   2075: =over 4
                   2076: 
                   2077: =item * B<variable>: 
                   2078: 
                   2079: Does what it usually does: declare which helper variable to put the
                   2080: result in.
                   2081: 
                   2082: =item * B<multichoice>: 
                   2083: 
                   2084: If true allows the user to select multiple students. Defaults to false.
                   2085: 
                   2086: =item * B<coursepersonnel>: 
                   2087: 
                   2088: If true adds the course personnel to the top of the student
                   2089: selection. Defaults to false.
                   2090: 
                   2091: =item * B<activeonly>:
                   2092: 
                   2093: If true, only active students and course personnel will be
                   2094: shown. Defaults to false.
                   2095: 
                   2096: =back
1.5       bowersj2 2097: 
                   2098: =cut
                   2099: 
                   2100: no strict;
                   2101: @ISA = ("Apache::lonhelper::element");
                   2102: use strict;
1.59      bowersj2 2103: use Apache::lonlocal;
1.5       bowersj2 2104: 
                   2105: 
                   2106: BEGIN {
1.7       bowersj2 2107:     &Apache::lonhelper::register('Apache::lonhelper::student',
1.5       bowersj2 2108:                               ('student'));
                   2109: }
                   2110: 
                   2111: sub new {
                   2112:     my $ref = Apache::lonhelper::element->new();
                   2113:     bless($ref);
                   2114: }
1.4       bowersj2 2115: 
1.5       bowersj2 2116: sub start_student {
1.4       bowersj2 2117:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   2118: 
                   2119:     if ($target ne 'helper') {
                   2120:         return '';
                   2121:     }
                   2122: 
1.5       bowersj2 2123:     $paramHash->{'variable'} = $token->[2]{'variable'};
                   2124:     $helper->declareVar($paramHash->{'variable'});
                   2125:     $paramHash->{'multichoice'} = $token->[2]{'multichoice'};
1.39      bowersj2 2126:     $paramHash->{'coursepersonnel'} = $token->[2]{'coursepersonnel'};
1.48      bowersj2 2127:     $paramHash->{'sctiveonly'} = $token->[2]{'activeonly'};
1.12      bowersj2 2128:     if (defined($token->[2]{'nextstate'})) {
                   2129:         $paramHash->{NEXTSTATE} = $token->[2]{'nextstate'};
                   2130:     }
                   2131:     
1.5       bowersj2 2132: }    
                   2133: 
                   2134: sub end_student {
                   2135:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   2136: 
                   2137:     if ($target ne 'helper') {
                   2138:         return '';
                   2139:     }
                   2140:     Apache::lonhelper::student->new();
1.3       bowersj2 2141: }
1.5       bowersj2 2142: 
                   2143: sub render {
                   2144:     my $self = shift;
                   2145:     my $result = '';
                   2146:     my $buttons = '';
1.18      bowersj2 2147:     my $var = $self->{'variable'};
1.5       bowersj2 2148: 
                   2149:     if ($self->{'multichoice'}) {
                   2150:         $result = <<SCRIPT;
                   2151: <script>
1.18      bowersj2 2152:     function checkall(value, checkName) {
1.15      bowersj2 2153: 	for (i=0; i<document.forms.helpform.elements.length; i++) {
1.18      bowersj2 2154:             ele = document.forms.helpform.elements[i];
                   2155:             if (ele.name == checkName + '.forminput') {
                   2156:                 document.forms.helpform.elements[i].checked=value;
                   2157:             }
1.5       bowersj2 2158:         }
                   2159:     }
1.58      sakharuk 2160:     function checksec(value) {
1.53      sakharuk 2161: 	for (i=0; i<document.forms.helpform.elements.length; i++) {
                   2162: 	    comp = document.forms.helpform.elements.chksec.value;
                   2163:             if (document.forms.helpform.elements[i].value.indexOf(':'+comp+':') != -1) {
1.82      sakharuk 2164: 		if (document.forms.helpform.elements[i].value.indexOf(':Active') != -1) {
                   2165: 		    document.forms.helpform.elements[i].checked=value;
                   2166: 		}
1.53      sakharuk 2167:             }
                   2168:         }
                   2169:     }
                   2170:     function checkactive() {
                   2171: 	for (i=0; i<document.forms.helpform.elements.length; i++) {
                   2172:             if (document.forms.helpform.elements[i].value.indexOf(':Active') != -1) {
                   2173:                 document.forms.helpform.elements[i].checked=true;
1.82      sakharuk 2174:             } 
                   2175:         }
                   2176:     }
                   2177:     function uncheckexpired() {
                   2178: 	for (i=0; i<document.forms.helpform.elements.length; i++) {
                   2179:             if (document.forms.helpform.elements[i].value.indexOf(':Expired') != -1) {
                   2180:                 document.forms.helpform.elements[i].checked=false;
                   2181:             } 
1.53      sakharuk 2182:         }
                   2183:     }
1.5       bowersj2 2184: </script>
                   2185: SCRIPT
1.59      bowersj2 2186: 
1.68      sakharuk 2187:         my %lt=&Apache::lonlocal::texthash(
                   2188:                     'ocs'  => "Select Only Current Students",
1.82      sakharuk 2189:                     'ues'  => "Unselect Expired Students",
1.68      sakharuk 2190:                     'sas'  => "Select All Students",
                   2191:                     'uas'  => "Unselect All Students",
1.82      sakharuk 2192:                     'sfsg' => "Select Current Students for Section/Group",
1.68      sakharuk 2193: 		    'ufsg' => "Unselect for Section/Group");
                   2194:  
1.5       bowersj2 2195:         $buttons = <<BUTTONS;
                   2196: <br />
1.92    ! foxr     2197: <table>
        !          2198:   <tr>
        !          2199:   
        !          2200:     <td><input type="button" onclick="checkactive()" value="$lt{'ocs'}" /></td>
        !          2201:     <td><input type="button" onclick="uncheckexpired()" value="$lt{'ues'}" /><br /></td>
        !          2202:   </tr>
        !          2203:   <tr>
        !          2204:      <td><input type="button" onclick="checkall(true, '$var')" value="$lt{'sas'}" /></td>
        !          2205:      <td> <input type="button" onclick="checkall(false, '$var')" value="$lt{'uas'}" /><br /></td>
        !          2206:   </tr>
        !          2207:   <tr>
        !          2208:       <td><input type="button" onclick="checksec(true)" value="$lt{'sfsg'}"></td>
        !          2209:       <td><input type="text" size="5" name="chksec">&nbsp;</td>
        !          2210:   </tr>
        !          2211:   <tr>
        !          2212:       <td><input type="button" onclick="checksec(false)" value="$lt{'ufsg'}"></td>
        !          2213:       <td></td>
        !          2214:   </tr>
        !          2215: </table>
1.5       bowersj2 2216: <br />
                   2217: BUTTONS
                   2218:     }
                   2219: 
                   2220:     if (defined $self->{ERROR_MSG}) {
                   2221:         $result .= '<font color="#FF0000">' . $self->{ERROR_MSG} . '</font><br /><br />';
                   2222:     }
                   2223: 
1.39      bowersj2 2224:     my $choices = [];
                   2225: 
                   2226:     # Load up the non-students, if necessary
                   2227:     if ($self->{'coursepersonnel'}) {
                   2228: 	my %coursepersonnel = Apache::lonnet::get_course_adv_roles();
                   2229: 	for (sort keys %coursepersonnel) {
                   2230: 	    for my $role (split /,/, $coursepersonnel{$_}) {
                   2231: 		# extract the names so we can sort them
                   2232: 		my @people;
                   2233: 		
                   2234: 		for (split /,/, $role) {
                   2235: 		    push @people, [split /:/, $role];
                   2236: 		}
                   2237: 		
                   2238: 		@people = sort { $a->[0] cmp $b->[0] } @people;
                   2239: 		
                   2240: 		for my $person (@people) {
                   2241: 		    push @$choices, [join(':', @$person), $person->[0], '', $_];
                   2242: 		}
                   2243: 	    }
                   2244: 	}
                   2245:     }
1.5       bowersj2 2246: 
                   2247:     # Constants
                   2248:     my $section = Apache::loncoursedata::CL_SECTION();
                   2249:     my $fullname = Apache::loncoursedata::CL_FULLNAME();
1.48      bowersj2 2250:     my $status = Apache::loncoursedata::CL_STATUS();
1.5       bowersj2 2251: 
1.39      bowersj2 2252:     # Load up the students
                   2253:     my $classlist = &Apache::loncoursedata::get_classlist();
                   2254:     my @keys = keys %{$classlist};
1.5       bowersj2 2255:     # Sort by: Section, name
                   2256:     @keys = sort {
1.39      bowersj2 2257:         if ($classlist->{$a}->[$section] ne $classlist->{$b}->[$section]) {
                   2258:             return $classlist->{$a}->[$section] cmp $classlist->{$b}->[$section];
1.5       bowersj2 2259:         }
1.39      bowersj2 2260:         return $classlist->{$a}->[$fullname] cmp $classlist->{$b}->[$fullname];
1.5       bowersj2 2261:     } @keys;
                   2262: 
1.39      bowersj2 2263:     # username, fullname, section, type
                   2264:     for (@keys) {
1.48      bowersj2 2265: 	# Filter out inactive students if we've set "activeonly"
                   2266: 	if (!$self->{'activeonly'} || $classlist->{$_}->[$status] eq
                   2267: 	    'Active') {
                   2268: 	    push @$choices, [$_, $classlist->{$_}->[$fullname], 
1.53      sakharuk 2269: 			     $classlist->{$_}->[$section],
                   2270: 			     $classlist->{$_}->[$status], 'Student'];
1.48      bowersj2 2271: 	}
1.39      bowersj2 2272:     }
                   2273: 
1.68      sakharuk 2274:     my $name = $self->{'coursepersonnel'} ? &mt('Name') : &mt('Student Name');
1.5       bowersj2 2275:     my $type = 'radio';
                   2276:     if ($self->{'multichoice'}) { $type = 'checkbox'; }
                   2277:     $result .= "<table cellspacing='2' cellpadding='2' border='0'>\n";
1.39      bowersj2 2278:     $result .= "<tr><td></td><td align='center'><b>$name</b></td>".
1.59      bowersj2 2279:         "<td align='center'><b>" . &mt('Section') . "</b></td>" . 
1.68      sakharuk 2280: 	"<td align='center'><b>".&mt('Status')."</b></td>" . 
                   2281: 	"<td align='center'><b>" . &mt("Role") . "</b></td>" .
                   2282: 	"<td align='center'><b>".&mt('Username').":".&mt('Domain')."</b></td></tr>";
1.5       bowersj2 2283: 
                   2284:     my $checked = 0;
1.39      bowersj2 2285:     for my $choice (@$choices) {
1.5       bowersj2 2286:         $result .= "<tr><td><input type='$type' name='" .
                   2287:             $self->{'variable'} . '.forminput' . "'";
                   2288:             
                   2289:         if (!$self->{'multichoice'} && !$checked) {
                   2290:             $result .= " checked ";
                   2291:             $checked = 1;
                   2292:         }
                   2293:         $result .=
1.89      foxr     2294:             " value='" . HTML::Entities::encode($choice->[0] . ':' 
                   2295: 						.$choice->[2] . ':' 
                   2296: 						.$choice->[1] . ':' 
                   2297: 						.$choice->[3], "<>&\"'")
1.5       bowersj2 2298:             . "' /></td><td>"
1.67      albertel 2299:             . HTML::Entities::encode($choice->[1],'<>&"')
1.5       bowersj2 2300:             . "</td><td align='center'>" 
1.67      albertel 2301:             . HTML::Entities::encode($choice->[2],'<>&"')
1.39      bowersj2 2302:             . "</td>\n<td>" 
1.67      albertel 2303: 	    . HTML::Entities::encode($choice->[3],'<>&"')
1.53      sakharuk 2304:             . "</td>\n<td>" 
1.67      albertel 2305: 	    . HTML::Entities::encode($choice->[4],'<>&"')
1.53      sakharuk 2306:             . "</td>\n<td>" 
1.67      albertel 2307: 	    . HTML::Entities::encode($choice->[0],'<>&"')
1.53      sakharuk 2308: 	    . "</td></tr>\n";
1.5       bowersj2 2309:     }
                   2310: 
                   2311:     $result .= "</table>\n\n";
                   2312:     $result .= $buttons;    
1.4       bowersj2 2313:     
1.5       bowersj2 2314:     return $result;
                   2315: }
                   2316: 
1.6       bowersj2 2317: sub postprocess {
                   2318:     my $self = shift;
                   2319: 
                   2320:     my $result = $ENV{'form.' . $self->{'variable'} . '.forminput'};
                   2321:     if (!$result) {
1.59      bowersj2 2322:         $self->{ERROR_MSG} = 
                   2323: 	    &mt('You must choose at least one student to continue.');
1.6       bowersj2 2324:         return 0;
                   2325:     }
                   2326: 
                   2327:     if (defined($self->{NEXTSTATE})) {
                   2328:         $helper->changeState($self->{NEXTSTATE});
                   2329:     }
                   2330: 
                   2331:     return 1;
                   2332: }
                   2333: 
1.5       bowersj2 2334: 1;
                   2335: 
                   2336: package Apache::lonhelper::files;
                   2337: 
                   2338: =pod
                   2339: 
1.44      bowersj2 2340: =head2 Element: filesX<files, helper element>
1.5       bowersj2 2341: 
                   2342: files allows the users to choose files from a given directory on the
                   2343: server. It is always multichoice and stores the result as a triple-pipe
                   2344: delimited entry in the helper variables. 
                   2345: 
                   2346: Since it is extremely unlikely that you can actually code a constant
                   2347: representing the directory you wish to allow the user to search, <files>
                   2348: takes a subroutine that returns the name of the directory you wish to
                   2349: have the user browse.
                   2350: 
                   2351: files accepts the attribute "variable" to control where the files chosen
                   2352: are put. It accepts the attribute "multichoice" as the other attribute,
                   2353: defaulting to false, which if true will allow the user to select more
                   2354: then one choice. 
                   2355: 
1.44      bowersj2 2356: <files> accepts three subtags: 
                   2357: 
                   2358: =over 4
                   2359: 
                   2360: =item * B<nextstate>: works as it does with the other tags. 
                   2361: 
                   2362: =item * B<filechoice>: When the contents of this tag are surrounded by
                   2363:     "sub {" and "}", will return a string representing what directory
                   2364:     on the server to allow the user to choose files from. 
                   2365: 
                   2366: =item * B<filefilter>: Should contain Perl code that when surrounded
                   2367:     by "sub { my $filename = shift; " and "}", returns a true value if
                   2368:     the user can pick that file, or false otherwise. The filename
                   2369:     passed to the function will be just the name of the file, with no
                   2370:     path info. By default, a filter function will be used that will
                   2371:     mask out old versions of files. This function is available as
                   2372:     Apache::lonhelper::files::not_old_version if you want to use it to
                   2373:     composite your own filters.
                   2374: 
                   2375: =back
                   2376: 
                   2377: B<General security note>: You should ensure the user can not somehow 
                   2378: pass something into your code that would allow them to look places 
                   2379: they should not be able to see, like the C</etc/> directory. However,
                   2380: the security impact would be minimal, since it would only expose
                   2381: the existence of files, there should be no way to parlay that into
                   2382: viewing the files. 
1.5       bowersj2 2383: 
                   2384: =cut
                   2385: 
                   2386: no strict;
                   2387: @ISA = ("Apache::lonhelper::element");
                   2388: use strict;
1.59      bowersj2 2389: use Apache::lonlocal;
1.5       bowersj2 2390: 
1.32      bowersj2 2391: use Apache::lonpubdir; # for getTitleString
                   2392: 
1.5       bowersj2 2393: BEGIN {
1.7       bowersj2 2394:     &Apache::lonhelper::register('Apache::lonhelper::files',
                   2395:                                  ('files', 'filechoice', 'filefilter'));
1.5       bowersj2 2396: }
                   2397: 
1.44      bowersj2 2398: sub not_old_version {
                   2399:     my $file = shift;
                   2400:     
                   2401:     # Given a file name, return false if it is an "old version" of a
                   2402:     # file, or true if it is not.
                   2403: 
                   2404:     if ($file =~ /^.*\.[0-9]+\.[A-Za-z]+(\.meta)?$/) {
                   2405: 	return 0;
                   2406:     }
                   2407:     return 1;
                   2408: }
                   2409: 
1.5       bowersj2 2410: sub new {
                   2411:     my $ref = Apache::lonhelper::element->new();
                   2412:     bless($ref);
                   2413: }
                   2414: 
                   2415: sub start_files {
                   2416:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   2417: 
                   2418:     if ($target ne 'helper') {
                   2419:         return '';
                   2420:     }
                   2421:     $paramHash->{'variable'} = $token->[2]{'variable'};
                   2422:     $helper->declareVar($paramHash->{'variable'});
                   2423:     $paramHash->{'multichoice'} = $token->[2]{'multichoice'};
                   2424: }    
                   2425: 
                   2426: sub end_files {
                   2427:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   2428: 
                   2429:     if ($target ne 'helper') {
                   2430:         return '';
                   2431:     }
                   2432:     if (!defined($paramHash->{FILTER_FUNC})) {
                   2433:         $paramHash->{FILTER_FUNC} = sub { return 1; };
                   2434:     }
                   2435:     Apache::lonhelper::files->new();
                   2436: }    
                   2437: 
                   2438: sub start_filechoice {
                   2439:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   2440: 
                   2441:     if ($target ne 'helper') {
                   2442:         return '';
                   2443:     }
                   2444:     $paramHash->{'filechoice'} = Apache::lonxml::get_all_text('/filechoice',
                   2445:                                                               $parser);
                   2446: }
                   2447: 
                   2448: sub end_filechoice { return ''; }
                   2449: 
                   2450: sub start_filefilter {
                   2451:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   2452: 
                   2453:     if ($target ne 'helper') {
                   2454:         return '';
                   2455:     }
                   2456: 
                   2457:     my $contents = Apache::lonxml::get_all_text('/filefilter',
                   2458:                                                 $parser);
                   2459:     $contents = 'sub { my $filename = shift; ' . $contents . '}';
                   2460:     $paramHash->{FILTER_FUNC} = eval $contents;
                   2461: }
                   2462: 
                   2463: sub end_filefilter { return ''; }
1.3       bowersj2 2464: 
1.87      matthew  2465: { 
                   2466:     # used to generate unique id attributes for <input> tags. 
                   2467:     # internal use only.
                   2468:     my $id=0;
                   2469:     sub new_id { return $id++;}
                   2470: }
                   2471: 
1.3       bowersj2 2472: sub render {
                   2473:     my $self = shift;
1.5       bowersj2 2474:     my $result = '';
                   2475:     my $var = $self->{'variable'};
                   2476:     
                   2477:     my $subdirFunc = eval('sub {' . $self->{'filechoice'} . '}');
1.11      bowersj2 2478:     die 'Error in resource filter code for variable ' . 
                   2479:         {'variable'} . ', Perl said:' . $@ if $@;
                   2480: 
1.5       bowersj2 2481:     my $subdir = &$subdirFunc();
                   2482: 
                   2483:     my $filterFunc = $self->{FILTER_FUNC};
1.44      bowersj2 2484:     if (!defined($filterFunc)) {
                   2485: 	$filterFunc = &not_old_version;
                   2486:     }
1.5       bowersj2 2487:     my $buttons = '';
1.22      bowersj2 2488:     my $type = 'radio';
                   2489:     if ($self->{'multichoice'}) {
                   2490:         $type = 'checkbox';
                   2491:     }
1.5       bowersj2 2492: 
                   2493:     if ($self->{'multichoice'}) {
                   2494:         $result = <<SCRIPT;
                   2495: <script>
1.18      bowersj2 2496:     function checkall(value, checkName) {
1.15      bowersj2 2497: 	for (i=0; i<document.forms.helpform.elements.length; i++) {
                   2498:             ele = document.forms.helpform.elements[i];
1.18      bowersj2 2499:             if (ele.name == checkName + '.forminput') {
1.15      bowersj2 2500:                 document.forms.helpform.elements[i].checked=value;
1.5       bowersj2 2501:             }
                   2502:         }
                   2503:     }
1.21      bowersj2 2504: 
1.22      bowersj2 2505:     function checkallclass(value, className) {
1.21      bowersj2 2506:         for (i=0; i<document.forms.helpform.elements.length; i++) {
                   2507:             ele = document.forms.helpform.elements[i];
1.22      bowersj2 2508:             if (ele.type == "$type" && ele.onclick) {
1.21      bowersj2 2509:                 document.forms.helpform.elements[i].checked=value;
                   2510:             }
                   2511:         }
                   2512:     }
1.5       bowersj2 2513: </script>
                   2514: SCRIPT
1.68      sakharuk 2515:        my %lt=&Apache::lonlocal::texthash(
                   2516: 			'saf'  => "Select All Files",
                   2517: 		        'uaf'  => "Unselect All Files");
                   2518:        $buttons = <<BUTTONS;
1.5       bowersj2 2519: <br /> &nbsp;
1.68      sakharuk 2520: <input type="button" onclick="checkall(true, '$var')" value="$lt{'saf'}" />
                   2521: <input type="button" onclick="checkall(false, '$var')" value="$lt{'uaf'}" />
1.23      bowersj2 2522: BUTTONS
                   2523: 
1.69      sakharuk 2524:        %lt=&Apache::lonlocal::texthash(
1.68      sakharuk 2525: 			'sap'  => "Select All Published",
                   2526: 		        'uap'  => "Unselect All Published");
1.23      bowersj2 2527:         if ($helper->{VARS}->{'construction'}) {
1.68      sakharuk 2528:        $buttons .= <<BUTTONS;
                   2529: <input type="button" onclick="checkallclass(true, 'Published')" value="$lt{'sap'}" />
                   2530: <input type="button" onclick="checkallclass(false, 'Published')" value="$lt{'uap'}" />
1.5       bowersj2 2531: <br /> &nbsp;
                   2532: BUTTONS
1.23      bowersj2 2533:        }
1.5       bowersj2 2534:     }
                   2535: 
                   2536:     # Get the list of files in this directory.
                   2537:     my @fileList;
                   2538: 
                   2539:     # If the subdirectory is in local CSTR space
1.47      albertel 2540:     my $metadir;
                   2541:     if ($subdir =~ m|/home/([^/]+)/public_html/(.*)|) {
1.5       bowersj2 2542:         my $user = $1;
                   2543:         my $domain = $Apache::lonnet::perlvar{'lonDefDomain'};
1.47      albertel 2544: 	$metadir='/res/'.$domain.'/'.$user.'/'.$2;
                   2545:         @fileList = &Apache::lonnet::dirlist($subdir, $domain, $user, '');
                   2546:     } elsif ($subdir =~ m|^~([^/]+)/(.*)$|) {
                   2547: 	$subdir='/home/'.$1.'/public_html/'.$2;
                   2548:         my $user = $1;
                   2549:         my $domain = $Apache::lonnet::perlvar{'lonDefDomain'};
                   2550: 	$metadir='/res/'.$domain.'/'.$user.'/'.$2;
1.5       bowersj2 2551:         @fileList = &Apache::lonnet::dirlist($subdir, $domain, $user, '');
                   2552:     } else {
                   2553:         # local library server resource space
                   2554:         @fileList = &Apache::lonnet::dirlist($subdir, $ENV{'user.domain'}, $ENV{'user.name'}, '');
                   2555:     }
1.3       bowersj2 2556: 
1.44      bowersj2 2557:     # Sort the fileList into order
1.85      albertel 2558:     @fileList = sort {lc($a) cmp lc($b)} @fileList;
1.44      bowersj2 2559: 
1.5       bowersj2 2560:     $result .= $buttons;
                   2561: 
1.6       bowersj2 2562:     if (defined $self->{ERROR_MSG}) {
                   2563:         $result .= '<br /><font color="#FF0000">' . $self->{ERROR_MSG} . '</font><br /><br />';
                   2564:     }
                   2565: 
1.20      bowersj2 2566:     $result .= '<table border="0" cellpadding="2" cellspacing="0">';
1.5       bowersj2 2567: 
                   2568:     # Keeps track if there are no choices, prints appropriate error
                   2569:     # if there are none. 
                   2570:     my $choices = 0;
                   2571:     # Print each legitimate file choice.
                   2572:     for my $file (@fileList) {
                   2573:         $file = (split(/&/, $file))[0];
                   2574:         if ($file eq '.' || $file eq '..') {
                   2575:             next;
                   2576:         }
                   2577:         my $fileName = $subdir .'/'. $file;
                   2578:         if (&$filterFunc($file)) {
1.24      sakharuk 2579: 	    my $status;
                   2580: 	    my $color;
                   2581: 	    if ($helper->{VARS}->{'construction'}) {
                   2582: 		($status, $color) = @{fileState($subdir, $file)};
                   2583: 	    } else {
                   2584: 		$status = '';
                   2585: 		$color = '';
                   2586: 	    }
1.22      bowersj2 2587: 
1.32      bowersj2 2588:             # Get the title
1.47      albertel 2589:             my $title = Apache::lonpubdir::getTitleString(($metadir?$metadir:$subdir) .'/'. $file);
1.32      bowersj2 2590: 
1.22      bowersj2 2591:             # Netscape 4 is stupid and there's nowhere to put the
                   2592:             # information on the input tag that the file is Published,
                   2593:             # Unpublished, etc. In *real* browsers we can just say
                   2594:             # "class='Published'" and check the className attribute of
                   2595:             # the input tag, but Netscape 4 is too stupid to understand
                   2596:             # that attribute, and un-comprehended attributes are not
                   2597:             # reflected into the object model. So instead, what I do 
                   2598:             # is either have or don't have an "onclick" handler that 
                   2599:             # does nothing, give Published files the onclick handler, and
                   2600:             # have the checker scripts check for that. Stupid and clumsy,
                   2601:             # and only gives us binary "yes/no" information (at least I
                   2602:             # couldn't figure out how to reach into the event handler's
                   2603:             # actual code to retreive a value), but it works well enough
                   2604:             # here.
1.23      bowersj2 2605:         
1.22      bowersj2 2606:             my $onclick = '';
1.23      bowersj2 2607:             if ($status eq 'Published' && $helper->{VARS}->{'construction'}) {
1.22      bowersj2 2608:                 $onclick = 'onclick="a=1" ';
                   2609:             }
1.87      matthew  2610:             my $id = &new_id();
1.20      bowersj2 2611:             $result .= '<tr><td align="right"' . " bgcolor='$color'>" .
1.22      bowersj2 2612:                 "<input $onclick type='$type' name='" . $var
1.89      foxr     2613:             . ".forminput' ".qq{id="$id"}." value='" . HTML::Entities::encode($fileName,"<>&\"'").
1.5       bowersj2 2614:                 "'";
                   2615:             if (!$self->{'multichoice'} && $choices == 0) {
                   2616:                 $result .= ' checked';
                   2617:             }
1.87      matthew  2618:             $result .= "/></td><td bgcolor='$color'>".
                   2619:                 qq{<label for="$id">}. $file . "</label></td>" .
1.32      bowersj2 2620:                 "<td bgcolor='$color'>$title</td>" .
                   2621:                 "<td bgcolor='$color'>$status</td>" . "</tr>\n";
1.5       bowersj2 2622:             $choices++;
                   2623:         }
                   2624:     }
                   2625: 
                   2626:     $result .= "</table>\n";
                   2627: 
                   2628:     if (!$choices) {
1.47      albertel 2629:         $result .= '<font color="#FF0000">There are no files available to select in this directory ('.$subdir.'). Please go back and select another option.</font><br /><br />';
1.5       bowersj2 2630:     }
                   2631: 
                   2632:     $result .= $buttons;
                   2633: 
                   2634:     return $result;
1.20      bowersj2 2635: }
                   2636: 
                   2637: # Determine the state of the file: Published, unpublished, modified.
                   2638: # Return the color it should be in and a label as a two-element array
                   2639: # reference.
                   2640: # Logic lifted from lonpubdir.pm, even though I don't know that it's still
                   2641: # the most right thing to do.
                   2642: 
                   2643: sub fileState {
                   2644:     my $constructionSpaceDir = shift;
                   2645:     my $file = shift;
                   2646:     
1.86      albertel 2647:     my ($uname,$udom)=($ENV{'user.name'},$ENV{'user.domain'});
                   2648:     if ($ENV{'request.role'}=~/^ca\./) {
                   2649: 	(undef,$udom,$uname)=split(/\//,$ENV{'request.role'});
                   2650:     }
1.20      bowersj2 2651:     my $docroot = $Apache::lonnet::perlvar{'lonDocRoot'};
                   2652:     my $subdirpart = $constructionSpaceDir;
1.86      albertel 2653:     $subdirpart =~ s/^\/home\/$uname\/public_html//;
                   2654:     my $resdir = $docroot . '/res/' . $udom . '/' . $uname .
1.20      bowersj2 2655:         $subdirpart;
                   2656: 
                   2657:     my @constructionSpaceFileStat = stat($constructionSpaceDir . '/' . $file);
                   2658:     my @resourceSpaceFileStat = stat($resdir . '/' . $file);
                   2659:     if (!@resourceSpaceFileStat) {
                   2660:         return ['Unpublished', '#FFCCCC'];
                   2661:     }
                   2662: 
                   2663:     my $constructionSpaceFileModified = $constructionSpaceFileStat[9];
                   2664:     my $resourceSpaceFileModified = $resourceSpaceFileStat[9];
                   2665:     
                   2666:     if ($constructionSpaceFileModified > $resourceSpaceFileModified) {
                   2667:         return ['Modified', '#FFFFCC'];
                   2668:     }
                   2669:     return ['Published', '#CCFFCC'];
1.4       bowersj2 2670: }
1.5       bowersj2 2671: 
1.4       bowersj2 2672: sub postprocess {
                   2673:     my $self = shift;
1.6       bowersj2 2674:     my $result = $ENV{'form.' . $self->{'variable'} . '.forminput'};
                   2675:     if (!$result) {
                   2676:         $self->{ERROR_MSG} = 'You must choose at least one file '.
                   2677:             'to continue.';
                   2678:         return 0;
                   2679:     }
                   2680: 
1.5       bowersj2 2681:     if (defined($self->{NEXTSTATE})) {
                   2682:         $helper->changeState($self->{NEXTSTATE});
1.3       bowersj2 2683:     }
1.6       bowersj2 2684: 
                   2685:     return 1;
1.3       bowersj2 2686: }
1.8       bowersj2 2687: 
                   2688: 1;
                   2689: 
1.11      bowersj2 2690: package Apache::lonhelper::section;
                   2691: 
                   2692: =pod
                   2693: 
1.44      bowersj2 2694: =head2 Element: sectionX<section, helper element>
1.11      bowersj2 2695: 
                   2696: <section> allows the user to choose one or more sections from the current
                   2697: course.
                   2698: 
                   2699: It takes the standard attributes "variable", "multichoice", and
                   2700: "nextstate", meaning what they do for most other elements.
                   2701: 
                   2702: =cut
                   2703: 
                   2704: no strict;
                   2705: @ISA = ("Apache::lonhelper::choices");
                   2706: use strict;
                   2707: 
                   2708: BEGIN {
                   2709:     &Apache::lonhelper::register('Apache::lonhelper::section',
                   2710:                                  ('section'));
                   2711: }
                   2712: 
                   2713: sub new {
                   2714:     my $ref = Apache::lonhelper::choices->new();
                   2715:     bless($ref);
                   2716: }
                   2717: 
                   2718: sub start_section {
                   2719:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   2720: 
                   2721:     if ($target ne 'helper') {
                   2722:         return '';
                   2723:     }
1.12      bowersj2 2724: 
                   2725:     $paramHash->{CHOICES} = [];
                   2726: 
1.11      bowersj2 2727:     $paramHash->{'variable'} = $token->[2]{'variable'};
                   2728:     $helper->declareVar($paramHash->{'variable'});
                   2729:     $paramHash->{'multichoice'} = $token->[2]{'multichoice'};
                   2730:     if (defined($token->[2]{'nextstate'})) {
1.12      bowersj2 2731:         $paramHash->{NEXTSTATE} = $token->[2]{'nextstate'};
1.11      bowersj2 2732:     }
                   2733: 
                   2734:     # Populate the CHOICES element
                   2735:     my %choices;
                   2736: 
                   2737:     my $section = Apache::loncoursedata::CL_SECTION();
                   2738:     my $classlist = Apache::loncoursedata::get_classlist();
                   2739:     foreach (keys %$classlist) {
                   2740:         my $sectionName = $classlist->{$_}->[$section];
                   2741:         if (!$sectionName) {
                   2742:             $choices{"No section assigned"} = "";
                   2743:         } else {
                   2744:             $choices{$sectionName} = $sectionName;
                   2745:         }
1.12      bowersj2 2746:     } 
                   2747:    
1.11      bowersj2 2748:     for my $sectionName (sort(keys(%choices))) {
1.12      bowersj2 2749:         
1.11      bowersj2 2750:         push @{$paramHash->{CHOICES}}, [$sectionName, $sectionName];
                   2751:     }
                   2752: }    
                   2753: 
1.12      bowersj2 2754: sub end_section {
                   2755:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
1.11      bowersj2 2756: 
1.12      bowersj2 2757:     if ($target ne 'helper') {
                   2758:         return '';
                   2759:     }
                   2760:     Apache::lonhelper::section->new();
                   2761: }    
1.11      bowersj2 2762: 1;
                   2763: 
1.34      bowersj2 2764: package Apache::lonhelper::string;
                   2765: 
                   2766: =pod
                   2767: 
1.44      bowersj2 2768: =head2 Element: stringX<string, helper element>
1.34      bowersj2 2769: 
                   2770: string elements provide a string entry field for the user. string elements
                   2771: take the usual 'variable' and 'nextstate' parameters. string elements
                   2772: also pass through 'maxlength' and 'size' attributes to the input tag.
                   2773: 
                   2774: string honors the defaultvalue tag, if given.
                   2775: 
1.38      bowersj2 2776: string honors the validation function, if given.
                   2777: 
1.34      bowersj2 2778: =cut
                   2779: 
                   2780: no strict;
                   2781: @ISA = ("Apache::lonhelper::element");
                   2782: use strict;
1.76      sakharuk 2783: use Apache::lonlocal;
1.34      bowersj2 2784: 
                   2785: BEGIN {
                   2786:     &Apache::lonhelper::register('Apache::lonhelper::string',
                   2787:                               ('string'));
                   2788: }
                   2789: 
                   2790: sub new {
                   2791:     my $ref = Apache::lonhelper::element->new();
                   2792:     bless($ref);
                   2793: }
                   2794: 
                   2795: # CONSTRUCTION: Construct the message element from the XML
                   2796: sub start_string {
                   2797:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   2798: 
                   2799:     if ($target ne 'helper') {
                   2800:         return '';
                   2801:     }
                   2802: 
                   2803:     $paramHash->{'variable'} = $token->[2]{'variable'};
                   2804:     $helper->declareVar($paramHash->{'variable'});
                   2805:     $paramHash->{'nextstate'} = $token->[2]{'nextstate'};
                   2806:     $paramHash->{'maxlength'} = $token->[2]{'maxlength'};
                   2807:     $paramHash->{'size'} = $token->[2]{'size'};
                   2808: 
                   2809:     return '';
                   2810: }
                   2811: 
                   2812: sub end_string {
                   2813:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   2814: 
                   2815:     if ($target ne 'helper') {
                   2816:         return '';
                   2817:     }
                   2818:     Apache::lonhelper::string->new();
                   2819:     return '';
                   2820: }
                   2821: 
                   2822: sub render {
                   2823:     my $self = shift;
1.38      bowersj2 2824:     my $result = '';
                   2825: 
                   2826:     if (defined $self->{ERROR_MSG}) {
                   2827:         $result .= '<br /><font color="#FF0000">' . $self->{ERROR_MSG} . '</font><br /><br />';
                   2828:     }
                   2829: 
                   2830:     $result .= '<input type="string" name="' . $self->{'variable'} . '.forminput"';
1.34      bowersj2 2831: 
                   2832:     if (defined($self->{'size'})) {
                   2833:         $result .= ' size="' . $self->{'size'} . '"';
                   2834:     }
                   2835:     if (defined($self->{'maxlength'})) {
                   2836:         $result .= ' maxlength="' . $self->{'maxlength'} . '"';
                   2837:     }
                   2838: 
                   2839:     if (defined($self->{DEFAULT_VALUE})) {
                   2840:         my $valueFunc = eval($self->{DEFAULT_VALUE});
                   2841:         die 'Error in default value code for variable ' . 
                   2842:             $self->{'variable'} . ', Perl said: ' . $@ if $@;
                   2843:         $result .= ' value="' . &$valueFunc($helper, $self) . '"';
                   2844:     }
                   2845: 
                   2846:     $result .= ' />';
                   2847: 
                   2848:     return $result;
                   2849: }
                   2850: 
                   2851: # If a NEXTSTATE was given, switch to it
                   2852: sub postprocess {
                   2853:     my $self = shift;
1.38      bowersj2 2854: 
                   2855:     if (defined($self->{VALIDATOR})) {
                   2856: 	my $validator = eval($self->{VALIDATOR});
                   2857: 	die 'Died during evaluation of evaulation code; Perl said: ' . $@ if $@;
                   2858: 	my $invalid = &$validator($helper, $state, $self, $self->getValue());
                   2859: 	if ($invalid) {
                   2860: 	    $self->{ERROR_MSG} = $invalid;
                   2861: 	    return 0;
                   2862: 	}
                   2863:     }
                   2864: 
                   2865:     if (defined($self->{'nextstate'})) {
                   2866:         $helper->changeState($self->{'nextstate'});
1.34      bowersj2 2867:     }
                   2868: 
                   2869:     return 1;
                   2870: }
                   2871: 
                   2872: 1;
                   2873: 
1.8       bowersj2 2874: package Apache::lonhelper::general;
                   2875: 
                   2876: =pod
                   2877: 
1.44      bowersj2 2878: =head2 General-purpose tag: <exec>X<exec, helper tag>
1.8       bowersj2 2879: 
1.44      bowersj2 2880: The contents of the exec tag are executed as Perl code, B<not> inside a 
1.8       bowersj2 2881: safe space, so the full range of $ENV and such is available. The code
                   2882: will be executed as a subroutine wrapped with the following code:
                   2883: 
                   2884: "sub { my $helper = shift; my $state = shift;" and
                   2885: 
                   2886: "}"
                   2887: 
                   2888: The return value is ignored.
                   2889: 
                   2890: $helper is the helper object. Feel free to add methods to the helper
                   2891: object to support whatever manipulation you may need to do (for instance,
                   2892: overriding the form location if the state is the final state; see 
1.44      bowersj2 2893: parameter.helper for an example).
1.8       bowersj2 2894: 
                   2895: $state is the $paramHash that has currently been generated and may
                   2896: be manipulated by the code in exec. Note that the $state is not yet
                   2897: an actual state B<object>, it is just a hash, so do not expect to
                   2898: be able to call methods on it.
                   2899: 
                   2900: =cut
                   2901: 
1.83      sakharuk 2902: use Apache::lonlocal;
                   2903: 
1.8       bowersj2 2904: BEGIN {
                   2905:     &Apache::lonhelper::register('Apache::lonhelper::general',
1.11      bowersj2 2906:                                  'exec', 'condition', 'clause',
                   2907:                                  'eval');
1.8       bowersj2 2908: }
                   2909: 
                   2910: sub start_exec {
                   2911:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   2912: 
                   2913:     if ($target ne 'helper') {
                   2914:         return '';
                   2915:     }
                   2916:     
                   2917:     my $code = &Apache::lonxml::get_all_text('/exec', $parser);
                   2918:     
                   2919:     $code = eval ('sub { my $helper = shift; my $state = shift; ' .
                   2920:         $code . "}");
1.11      bowersj2 2921:     die 'Error in <exec>, Perl said: '. $@ if $@;
1.8       bowersj2 2922:     &$code($helper, $paramHash);
                   2923: }
                   2924: 
                   2925: sub end_exec { return ''; }
                   2926: 
                   2927: =pod
                   2928: 
                   2929: =head2 General-purpose tag: <condition>
                   2930: 
                   2931: The <condition> tag allows you to mask out parts of the helper code
                   2932: depending on some programatically determined condition. The condition
                   2933: tag contains a tag <clause> which contains perl code that when wrapped
                   2934: with "sub { my $helper = shift; my $state = shift; " and "}", returns
                   2935: a true value if the XML in the condition should be evaluated as a normal
                   2936: part of the helper, or false if it should be completely discarded.
                   2937: 
                   2938: The <clause> tag must be the first sub-tag of the <condition> tag or
                   2939: it will not work as expected.
                   2940: 
                   2941: =cut
                   2942: 
                   2943: # The condition tag just functions as a marker, it doesn't have
                   2944: # to "do" anything. Technically it doesn't even have to be registered
                   2945: # with the lonxml code, but I leave this here to be explicit about it.
                   2946: sub start_condition { return ''; }
                   2947: sub end_condition { return ''; }
                   2948: 
                   2949: sub start_clause {
                   2950:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   2951: 
                   2952:     if ($target ne 'helper') {
                   2953:         return '';
                   2954:     }
                   2955:     
                   2956:     my $clause = Apache::lonxml::get_all_text('/clause', $parser);
                   2957:     $clause = eval('sub { my $helper = shift; my $state = shift; '
                   2958:         . $clause . '}');
1.11      bowersj2 2959:     die 'Error in clause of condition, Perl said: ' . $@ if $@;
1.8       bowersj2 2960:     if (!&$clause($helper, $paramHash)) {
                   2961:         # Discard all text until the /condition.
                   2962:         &Apache::lonxml::get_all_text('/condition', $parser);
                   2963:     }
                   2964: }
                   2965: 
                   2966: sub end_clause { return ''; }
1.11      bowersj2 2967: 
                   2968: =pod
                   2969: 
1.44      bowersj2 2970: =head2 General-purpose tag: <eval>X<eval, helper tag>
1.11      bowersj2 2971: 
                   2972: The <eval> tag will be evaluated as a subroutine call passed in the
                   2973: current helper object and state hash as described in <condition> above,
                   2974: but is expected to return a string to be printed directly to the
                   2975: screen. This is useful for dynamically generating messages. 
                   2976: 
                   2977: =cut
                   2978: 
                   2979: # This is basically a type of message.
                   2980: # Programmatically setting $paramHash->{NEXTSTATE} would work, though
                   2981: # it's probably bad form.
                   2982: 
                   2983: sub start_eval {
                   2984:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   2985: 
                   2986:     if ($target ne 'helper') {
                   2987:         return '';
                   2988:     }
                   2989:     
                   2990:     my $program = Apache::lonxml::get_all_text('/eval', $parser);
                   2991:     $program = eval('sub { my $helper = shift; my $state = shift; '
                   2992:         . $program . '}');
                   2993:     die 'Error in eval code, Perl said: ' . $@ if $@;
                   2994:     $paramHash->{MESSAGE_TEXT} = &$program($helper, $paramHash);
                   2995: }
                   2996: 
                   2997: sub end_eval { 
                   2998:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   2999: 
                   3000:     if ($target ne 'helper') {
                   3001:         return '';
                   3002:     }
                   3003: 
                   3004:     Apache::lonhelper::message->new();
                   3005: }
                   3006: 
1.13      bowersj2 3007: 1;
                   3008: 
1.27      bowersj2 3009: package Apache::lonhelper::final;
                   3010: 
                   3011: =pod
                   3012: 
1.44      bowersj2 3013: =head2 Element: finalX<final, helper tag>
1.27      bowersj2 3014: 
                   3015: <final> is a special element that works with helpers that use the <finalcode>
1.44      bowersj2 3016: tagX<finalcode, helper tag>. It goes through all the states and elements, executing the <finalcode>
1.27      bowersj2 3017: snippets and collecting the results. Finally, it takes the user out of the
                   3018: helper, going to a provided page.
                   3019: 
1.34      bowersj2 3020: If the parameter "restartCourse" is true, this will override the buttons and
                   3021: will make a "Finish Helper" button that will re-initialize the course for them,
                   3022: which is useful for the Course Initialization helper so the users never see
                   3023: the old values taking effect.
                   3024: 
1.27      bowersj2 3025: =cut
                   3026: 
                   3027: no strict;
                   3028: @ISA = ("Apache::lonhelper::element");
                   3029: use strict;
1.62      matthew  3030: use Apache::lonlocal;
1.27      bowersj2 3031: BEGIN {
                   3032:     &Apache::lonhelper::register('Apache::lonhelper::final',
                   3033:                                  ('final', 'exitpage'));
                   3034: }
                   3035: 
                   3036: sub new {
                   3037:     my $ref = Apache::lonhelper::element->new();
                   3038:     bless($ref);
                   3039: }
                   3040: 
1.34      bowersj2 3041: sub start_final { 
                   3042:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   3043: 
                   3044:     if ($target ne 'helper') {
                   3045:         return '';
                   3046:     }
                   3047: 
                   3048:     $paramHash->{'restartCourse'} = $token->[2]{'restartCourse'};
                   3049: 
                   3050:     return ''; 
                   3051: }
1.27      bowersj2 3052: 
                   3053: sub end_final {
                   3054:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   3055: 
                   3056:     if ($target ne 'helper') {
                   3057:         return '';
                   3058:     }
                   3059: 
                   3060:     Apache::lonhelper::final->new();
                   3061:    
                   3062:     return '';
                   3063: }
                   3064: 
                   3065: sub start_exitpage {
                   3066:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   3067: 
                   3068:     if ($target ne 'helper') {
                   3069:         return '';
                   3070:     }
                   3071: 
                   3072:     $paramHash->{EXIT_PAGE} = &Apache::lonxml::get_all_text('/exitpage',
                   3073:                                                             $parser);
                   3074: 
                   3075:     return '';
                   3076: }
                   3077: 
                   3078: sub end_exitpage { return ''; }
                   3079: 
                   3080: sub render {
                   3081:     my $self = shift;
                   3082: 
                   3083:     my @results;
                   3084: 
                   3085:     # Collect all the results
                   3086:     for my $stateName (keys %{$helper->{STATES}}) {
                   3087:         my $state = $helper->{STATES}->{$stateName};
                   3088:         
                   3089:         for my $element (@{$state->{ELEMENTS}}) {
                   3090:             if (defined($element->{FINAL_CODE})) {
                   3091:                 # Compile the code.
1.31      bowersj2 3092:                 my $code = 'sub { my $helper = shift; my $element = shift; ' 
                   3093:                     . $element->{FINAL_CODE} . '}';
1.27      bowersj2 3094:                 $code = eval($code);
                   3095:                 die 'Error while executing final code for element with var ' .
                   3096:                     $element->{'variable'} . ', Perl said: ' . $@ if $@;
                   3097: 
1.31      bowersj2 3098:                 my $result = &$code($helper, $element);
1.27      bowersj2 3099:                 if ($result) {
                   3100:                     push @results, $result;
                   3101:                 }
                   3102:             }
                   3103:         }
                   3104:     }
                   3105: 
1.40      bowersj2 3106:     my $result;
1.27      bowersj2 3107: 
1.40      bowersj2 3108:     if (scalar(@results) != 0) {
                   3109: 	$result .= "<ul>\n";
                   3110: 	for my $re (@results) {
                   3111: 	    $result .= '    <li>' . $re . "</li>\n";
                   3112: 	}
                   3113: 	
                   3114: 	if (!@results) {
1.59      bowersj2 3115: 	    $result .= '    <li>' . 
                   3116: 		&mt('No changes were made to current settings.') . '</li>';
1.40      bowersj2 3117: 	}
                   3118: 	
                   3119: 	$result .= '</ul>';
1.34      bowersj2 3120:     }
                   3121: 
                   3122:     if ($self->{'restartCourse'}) {
1.45      bowersj2 3123: 	my $targetURL = '/adm/menu';
1.64      albertel 3124: 	if ($ENV{'course.'.$ENV{'request.course.id'}.'.url'}=~/^uploaded/) {
                   3125: 	    $targetURL = '/adm/coursedocs';
                   3126: 	} else {
                   3127: 	    $targetURL = '/adm/navmaps';
                   3128: 	}
1.45      bowersj2 3129: 	if ($ENV{'course.'.$ENV{'request.course.id'}.'.clonedfrom'}) {
                   3130: 	    $targetURL = '/adm/parmset?overview=1';
                   3131: 	}
1.59      bowersj2 3132: 	my $previous = HTML::Entities::encode(&mt("<- Previous"), '<>&"');
                   3133: 	my $next = HTML::Entities::encode(&mt("Next ->"), '<>&"');
1.34      bowersj2 3134:         $result .= "<center>\n" .
                   3135:             "<form action='/adm/roles' method='post' target='loncapaclient'>\n" .
1.59      bowersj2 3136:             "<input type='button' onclick='history.go(-1)' value='$previous' />" .
1.45      bowersj2 3137:             "<input type='hidden' name='orgurl' value='$targetURL' />" .
1.34      bowersj2 3138:             "<input type='hidden' name='selectrole' value='1' />\n" .
                   3139:             "<input type='hidden' name='" . $ENV{'request.role'} . 
1.59      bowersj2 3140:             "' value='1' />\n<input type='submit' value='" .
1.63      matthew  3141: 	    &mt('Finish Course Initialization') . "' />\n" .
1.34      bowersj2 3142:             "</form></center>";
                   3143:     }
                   3144: 
1.40      bowersj2 3145:     return $result;
1.34      bowersj2 3146: }
                   3147: 
                   3148: sub overrideForm {
                   3149:     my $self = shift;
                   3150:     return $self->{'restartCourse'};
1.27      bowersj2 3151: }
                   3152: 
                   3153: 1;
                   3154: 
1.13      bowersj2 3155: package Apache::lonhelper::parmwizfinal;
                   3156: 
                   3157: # This is the final state for the parmwizard. It is not generally useful,
                   3158: # so it is not perldoc'ed. It does its own processing.
                   3159: # It is represented with <parmwizfinal />, and
                   3160: # should later be moved to lonparmset.pm .
                   3161: 
                   3162: no strict;
                   3163: @ISA = ('Apache::lonhelper::element');
                   3164: use strict;
1.69      sakharuk 3165: use Apache::lonlocal;
1.11      bowersj2 3166: 
1.13      bowersj2 3167: BEGIN {
                   3168:     &Apache::lonhelper::register('Apache::lonhelper::parmwizfinal',
                   3169:                                  ('parmwizfinal'));
                   3170: }
                   3171: 
                   3172: use Time::localtime;
                   3173: 
                   3174: sub new {
                   3175:     my $ref = Apache::lonhelper::choices->new();
                   3176:     bless ($ref);
                   3177: }
                   3178: 
                   3179: sub start_parmwizfinal { return ''; }
                   3180: 
                   3181: sub end_parmwizfinal {
                   3182:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   3183: 
                   3184:     if ($target ne 'helper') {
                   3185:         return '';
                   3186:     }
                   3187:     Apache::lonhelper::parmwizfinal->new();
                   3188: }
                   3189: 
                   3190: # Renders a form that, when submitted, will form the input to lonparmset.pm
                   3191: sub render {
                   3192:     my $self = shift;
                   3193:     my $vars = $helper->{VARS};
                   3194: 
                   3195:     # FIXME: Unify my designators with the standard ones
1.48      bowersj2 3196:     my %dateTypeHash = ('open_date' => "opening date",
                   3197:                         'due_date' => "due date",
                   3198:                         'answer_date' => "answer date",
                   3199: 			'tries' => 'number of tries',
                   3200: 			'weight' => 'problem weight'
1.38      bowersj2 3201: 			);
1.13      bowersj2 3202:     my %parmTypeHash = ('open_date' => "0_opendate",
                   3203:                         'due_date' => "0_duedate",
1.38      bowersj2 3204:                         'answer_date' => "0_answerdate",
1.48      bowersj2 3205: 			'tries' => '0_maxtries',
                   3206: 			'weight' => '0_weight' );
1.13      bowersj2 3207:     
                   3208:     my $affectedResourceId = "";
                   3209:     my $parm_name = $parmTypeHash{$vars->{ACTION_TYPE}};
                   3210:     my $level = "";
1.27      bowersj2 3211:     my $resourceString;
                   3212:     my $symb;
                   3213:     my $paramlevel;
                   3214: 
1.13      bowersj2 3215:     # Print the granularity, depending on the action
                   3216:     if ($vars->{GRANULARITY} eq 'whole_course') {
1.76      sakharuk 3217:         $resourceString .= '<li>'.&mt('for <b>all resources in the course</b>').'</li>';
1.13      bowersj2 3218:         $level = 9; # general course, see lonparmset.pm perldoc
                   3219:         $affectedResourceId = "0.0";
1.27      bowersj2 3220:         $symb = 'a';
                   3221:         $paramlevel = 'general';
1.13      bowersj2 3222:     } elsif ($vars->{GRANULARITY} eq 'map') {
1.41      bowersj2 3223:         my $navmap = Apache::lonnavmaps::navmap->new();
1.35      bowersj2 3224:         my $res = $navmap->getByMapPc($vars->{RESOURCE_ID});
1.13      bowersj2 3225:         my $title = $res->compTitle();
1.27      bowersj2 3226:         $symb = $res->symb();
1.78      sakharuk 3227:         $resourceString .= '<li>'.&mt('for the map named [_1]',"<b>$title</b>").'</li>';
1.13      bowersj2 3228:         $level = 8;
                   3229:         $affectedResourceId = $vars->{RESOURCE_ID};
1.27      bowersj2 3230:         $paramlevel = 'map';
1.13      bowersj2 3231:     } else {
1.41      bowersj2 3232:         my $navmap = Apache::lonnavmaps::navmap->new();
1.13      bowersj2 3233:         my $res = $navmap->getById($vars->{RESOURCE_ID});
1.27      bowersj2 3234:         $symb = $res->symb();
1.13      bowersj2 3235:         my $title = $res->compTitle();
1.78      sakharuk 3236:         $resourceString .= '<li>'.&mt('for the resource named [_1]',"<b>$title</b>").'</li>';
1.13      bowersj2 3237:         $level = 7;
                   3238:         $affectedResourceId = $vars->{RESOURCE_ID};
1.27      bowersj2 3239:         $paramlevel = 'full';
1.13      bowersj2 3240:     }
                   3241: 
1.27      bowersj2 3242:     my $result = "<form name='helpform' method='get' action='/adm/parmset#$affectedResourceId&$parm_name&$level'>\n";
1.69      sakharuk 3243:     $result .= '<p>'.&mt('Confirm that this information is correct, then click &quot;Finish Helper&quot; to complete setting the parameter.').'<ul>';
1.27      bowersj2 3244:     
                   3245:     # Print the type of manipulation:
1.73      albertel 3246:     my $extra;
1.38      bowersj2 3247:     if ($vars->{ACTION_TYPE} eq 'tries') {
1.73      albertel 3248: 	$extra =  $vars->{TRIES};
1.38      bowersj2 3249:     }
1.48      bowersj2 3250:     if ($vars->{ACTION_TYPE} eq 'weight') {
1.73      albertel 3251: 	$extra =  $vars->{WEIGHT};
                   3252:     }
                   3253:     $result .= "<li>";
1.74      matthew  3254:     my $what = &mt($dateTypeHash{$vars->{ACTION_TYPE}});
1.73      albertel 3255:     if ($extra) {
                   3256: 	$result .= &mt('Setting the [_1] to [_2]',"<b>$what</b>",$extra);
                   3257:     } else {
                   3258: 	$result .= &mt('Setting the [_1]',"<b>$what</b>");
1.48      bowersj2 3259:     }
1.38      bowersj2 3260:     $result .= "</li>\n";
1.27      bowersj2 3261:     if ($vars->{ACTION_TYPE} eq 'due_date' || 
                   3262:         $vars->{ACTION_TYPE} eq 'answer_date') {
                   3263:         # for due dates, we default to "date end" type entries
                   3264:         $result .= "<input type='hidden' name='recent_date_end' " .
                   3265:             "value='" . $vars->{PARM_DATE} . "' />\n";
                   3266:         $result .= "<input type='hidden' name='pres_value' " . 
                   3267:             "value='" . $vars->{PARM_DATE} . "' />\n";
                   3268:         $result .= "<input type='hidden' name='pres_type' " .
                   3269:             "value='date_end' />\n";
                   3270:     } elsif ($vars->{ACTION_TYPE} eq 'open_date') {
                   3271:         $result .= "<input type='hidden' name='recent_date_start' ".
                   3272:             "value='" . $vars->{PARM_DATE} . "' />\n";
                   3273:         $result .= "<input type='hidden' name='pres_value' " .
                   3274:             "value='" . $vars->{PARM_DATE} . "' />\n";
                   3275:         $result .= "<input type='hidden' name='pres_type' " .
                   3276:             "value='date_start' />\n";
1.38      bowersj2 3277:     } elsif ($vars->{ACTION_TYPE} eq 'tries') {
                   3278: 	$result .= "<input type='hidden' name='pres_value' " .
                   3279: 	    "value='" . $vars->{TRIES} . "' />\n";
1.48      bowersj2 3280:     } elsif ($vars->{ACTION_TYPE} eq 'weight') {
                   3281: 	$result .= "<input type='hidden' name='pres_value' " .
                   3282: 	    "value='" . $vars->{WEIGHT} . "' />\n";
1.38      bowersj2 3283:     }
1.27      bowersj2 3284: 
                   3285:     $result .= $resourceString;
                   3286:     
1.13      bowersj2 3287:     # Print targets
                   3288:     if ($vars->{TARGETS} eq 'course') {
1.76      sakharuk 3289:         $result .= '<li>'.&mt('for <b>all students in course</b>').'</li>';
1.13      bowersj2 3290:     } elsif ($vars->{TARGETS} eq 'section') {
                   3291:         my $section = $vars->{SECTION_NAME};
1.79      sakharuk 3292:         $result .= '<li>'.&mt('for section [_1]',"<b>$section</b>").'</li>';
1.13      bowersj2 3293:         $level -= 3;
                   3294:         $result .= "<input type='hidden' name='csec' value='" .
1.89      foxr     3295:             HTML::Entities::encode($section,"'<>&\"") . "' />\n";
1.13      bowersj2 3296:     } else {
                   3297:         # FIXME: This is probably wasteful! Store the name!
                   3298:         my $classlist = Apache::loncoursedata::get_classlist();
1.27      bowersj2 3299:         my $username = $vars->{USER_NAME};
                   3300:         # Chop off everything after the last colon (section)
                   3301:         $username = substr($username, 0, rindex($username, ':'));
                   3302:         my $name = $classlist->{$username}->[6];
1.79      sakharuk 3303:         $result .= '<li>'.&mt('for [_1]',"<b>$name</b>").'</li>';
1.13      bowersj2 3304:         $level -= 6;
                   3305:         my ($uname, $udom) = split /:/, $vars->{USER_NAME};
                   3306:         $result .= "<input type='hidden' name='uname' value='".
1.89      foxr     3307:             HTML::Entities::encode($uname,"'<>&\"") . "' />\n";
1.13      bowersj2 3308:         $result .= "<input type='hidden' name='udom' value='".
1.89      foxr     3309:             HTML::Entities::encode($udom,"'<>&\"") . "' />\n";
1.13      bowersj2 3310:     }
                   3311: 
                   3312:     # Print value
1.48      bowersj2 3313:     if ($vars->{ACTION_TYPE} ne 'tries' && $vars->{ACTION_TYPE} ne 'weight') {
1.81      sakharuk 3314: 	$result .= '<li>'.&mt('to [_1] ([_2])',"<b>".ctime($vars->{PARM_DATE})."</b>",Apache::lonnavmaps::timeToHumanString($vars->{PARM_DATE}))."</li>\n";
1.38      bowersj2 3315:     }
                   3316:  
1.13      bowersj2 3317:     # print pres_marker
                   3318:     $result .= "\n<input type='hidden' name='pres_marker'" .
                   3319:         " value='$affectedResourceId&$parm_name&$level' />\n";
1.27      bowersj2 3320:     
                   3321:     # Make the table appear
                   3322:     $result .= "\n<input type='hidden' value='true' name='prevvisit' />";
                   3323:     $result .= "\n<input type='hidden' value='all' name='pschp' />";
                   3324:     $result .= "\n<input type='hidden' value='$symb' name='pssymb' />";
                   3325:     $result .= "\n<input type='hidden' value='$paramlevel' name='parmlev' />";
1.13      bowersj2 3326: 
1.71      sakharuk 3327:     $result .= "<br /><br /><center><input type='submit' value='".&mt('Finish Helper')."' /></center></form>\n";
1.13      bowersj2 3328: 
                   3329:     return $result;
                   3330: }
                   3331:     
                   3332: sub overrideForm {
                   3333:     return 1;
                   3334: }
1.5       bowersj2 3335: 
1.4       bowersj2 3336: 1;
1.3       bowersj2 3337: 
1.1       bowersj2 3338: __END__
1.3       bowersj2 3339: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>
500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.