--- loncom/interface/lonhelper.pm 2005/01/20 20:20:35 1.94 +++ loncom/interface/lonhelper.pm 2006/07/03 11:12:24 1.156 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # .helper XML handler to implement the LON-CAPA helper # -# $Id: lonhelper.pm,v 1.94 2005/01/20 20:20:35 albertel Exp $ +# $Id: lonhelper.pm,v 1.156 2006/07/03 11:12:24 foxr Exp $ # # Copyright Michigan State University Board of Trustees # @@ -25,10 +25,6 @@ # # http://www.lon-capa.org/ # -# (Page Handler -# -# (.helper handler -# =pod @@ -186,6 +182,10 @@ use Apache::Constants qw(:common); use Apache::File; use Apache::lonxml; use Apache::lonlocal; +use Apache::lonnet; +use Apache::longroup; +use Apache::lonselstudent; +use LONCAPA; # Register all the tags with the helper, so the helper can # push and pop them @@ -255,7 +255,7 @@ sub real_handler { my $r = shift; my $uri = shift; if (!defined($uri)) { $uri = $r->uri(); } - $ENV{'request.uri'} = $uri; + $env{'request.uri'} = $uri; my $filename = '/home/httpd/html' . $uri; my $fh = Apache::File->new($filename); my $file; @@ -263,7 +263,7 @@ sub real_handler { # Send header, don't cache this page - if ($ENV{'browser.mathml'}) { + if ($env{'browser.mathml'}) { &Apache::loncommon::content_type($r,'text/xml'); } else { &Apache::loncommon::content_type($r,'text/html'); @@ -278,7 +278,7 @@ sub real_handler { my $allowed = $helper->allowedCheck(); if (!$allowed) { - $ENV{'user.error.msg'} = $ENV{'request.uri'}.':'.$helper->{REQUIRED_PRIV}. + $env{'user.error.msg'} = $env{'request.uri'}.':'.$helper->{REQUIRED_PRIV}. ":0:0:Permission denied to access this helper."; return HTTP_NOT_ACCEPTABLE; } @@ -363,6 +363,8 @@ use HTML::Entities(); use Apache::loncommon; use Apache::File; use Apache::lonlocal; +use Apache::lonnet; +use LONCAPA; sub new { my $proto = shift; @@ -374,16 +376,16 @@ sub new { # If there is a state from the previous form, use that. If there is no # state, use the start state parameter. - if (defined $ENV{"form.CURRENT_STATE"}) + if (defined $env{"form.CURRENT_STATE"}) { - $self->{STATE} = $ENV{"form.CURRENT_STATE"}; + $self->{STATE} = $env{"form.CURRENT_STATE"}; } else { $self->{STATE} = "START"; } - $self->{TOKEN} = $ENV{'form.TOKEN'}; + $self->{TOKEN} = $env{'form.TOKEN'}; # If a token was passed, we load that in. Otherwise, we need to create a # new storage file # Tried to use standard Tie'd hashes, but you can't seem to take a @@ -416,16 +418,16 @@ sub new { return undef; } # Must create the storage - $self->{TOKEN} = md5_hex($ENV{'user.name'} . $ENV{'user.domain'} . + $self->{TOKEN} = md5_hex($env{'user.name'} . $env{'user.domain'} . time() . rand()); $self->{FILENAME} = $Apache::lonnet::tmpdir . md5_hex($self->{TOKEN}); } # OK, we now have our persistent storage. - if (defined $ENV{"form.RETURN_PAGE"}) + if (defined $env{"form.RETURN_PAGE"}) { - $self->{RETURN_PAGE} = $ENV{"form.RETURN_PAGE"}; + $self->{RETURN_PAGE} = $env{"form.RETURN_PAGE"}; } else { @@ -468,9 +470,8 @@ sub _saveVars { sub _varsInFile { my $self = shift; my @vars = (); - for my $key (keys %{$self->{VARS}}) { - push @vars, &Apache::lonnet::escape($key) . '=' . - &Apache::lonnet::escape($self->{VARS}->{$key}); + for my $key (keys(%{$self->{VARS}})) { + push(@vars, &escape($key) . '=' . &escape($self->{VARS}->{$key})); } return join ('&', @vars); } @@ -486,11 +487,11 @@ sub declareVar { } my $envname = 'form.' . $var . '.forminput'; - if (defined($ENV{$envname})) { - if (ref($ENV{$envname})) { - $self->{VARS}->{$var} = join('|||', @{$ENV{$envname}}); + if (defined($env{$envname})) { + if (ref($env{$envname})) { + $self->{VARS}->{$var} = join('|||', @{$env{$envname}}); } else { - $self->{VARS}->{$var} = $ENV{$envname}; + $self->{VARS}->{$var} = $env{$envname}; } } } @@ -502,7 +503,7 @@ sub allowedCheck { return 1; } - return Apache::lonnet::allowed($self->{REQUIRED_PRIV}, $ENV{'request.course.id'}); + return Apache::lonnet::allowed($self->{REQUIRED_PRIV}, $env{'request.course.id'}); } sub changeState { @@ -524,7 +525,7 @@ sub process { # Phase 1: Post processing for state of previous screen (which is actually # the "current state" in terms of the helper variables), if it wasn't the # beginning state. - if ($self->{STATE} ne "START" || $ENV{"form.SUBMIT"} eq &mt("Next ->")) { + if ($self->{STATE} ne "START" || $env{"form.SUBMIT"} eq &mt("Next ->")) { my $prevState = $self->{STATES}{$self->{STATE}}; $prevState->postprocess(); } @@ -576,21 +577,19 @@ sub display { # Phase 4: Display. my $stateTitle=&mt($state->title()); - my $helperTitle = &mt($self->{TITLE}); - my $bodytag = &Apache::loncommon::bodytag($helperTitle,'',''); + my $browser_searcher_js = + ''; + + $result .= &Apache::loncommon::start_page($self->{TITLE}, + $browser_searcher_js); + my $previous = HTML::Entities::encode(&mt("<- Previous"), '<>&"'); my $next = HTML::Entities::encode(&mt("Next ->"), '<>&"'); # FIXME: This should be parameterized, not concatenated - Jeremy - my $loncapaHelper = &mt("LON-CAPA Helper:"); - $result .= < - - - $loncapaHelper: $helperTitle - - $bodytag -HEADER + if (!$state->overrideForm()) { $result.="
"; } $result .= < @@ -653,10 +652,9 @@ HEADER - - FOOTER + $result .= &Apache::loncommon::end_page(); # Handle writing out the vars to the file my $file = Apache::File->new('>'.$self->{FILENAME}); print $file $self->_varsInFile(); @@ -1025,6 +1023,81 @@ sub postprocess { } 1; +package Apache::lonhelper::skip; + +=pod + +=head1 Elements + +=head2 Element: skipX + +The tag allows you define conditions under which the current state +should be skipped over and define what state to skip to. + + + + + #some code that decides whether to skip the state or not + + FINISH + + A possibly skipped state + + +=cut + +no strict; +@ISA = ("Apache::lonhelper::element"); +use strict; + +BEGIN { + &Apache::lonhelper::register('Apache::lonhelper::skip', + ('skip')); +} + +sub new { + my $ref = Apache::lonhelper::element->new(); + bless($ref); +} + +sub start_skip { + my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; + + if ($target ne 'helper') { + return ''; + } + # let know what text to skip to + $paramHash->{SKIPTAG}='/skip'; + return ''; +} + +sub end_skip { + my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; + + if ($target ne 'helper') { + return ''; + } + Apache::lonhelper::skip->new(); + return ''; +} + +sub render { + my $self = shift; + return ''; +} +# If a NEXTSTATE is set, switch to it +sub preprocess { + my ($self) = @_; + + if (defined($self->{NEXTSTATE})) { + $helper->changeState($self->{NEXTSTATE}); + } + + return 1; +} + +1; + package Apache::lonhelper::choices; =pod @@ -1074,6 +1147,16 @@ will be the state transistioned to if th the choice is not multichoice. This will override the nextstate passed to the parent C tag. + may optionally contain a 'relatedvalue' attribute, which +if present will cause a text entry to appear to the right of the +selection. The value of the relatedvalue attribute is a variable +into which the text entry will be stored e.g.: +[2]{'computer'}; my $human = &mt(&Apache::lonxml::get_all_text('/choice', $parser)); - my $nextstate = $token->[2]{'nextstate'}; - my $evalFlag = $token->[2]{'eval'}; + my $nextstate = $token->[2]{'nextstate'}; + my $evalFlag = $token->[2]{'eval'}; + my $relatedVar = $token->[2]{'relatedvalue'}; + my $relatedDefault = $token->[2]{'relateddefault'}; push @{$paramHash->{CHOICES}}, [&mtn($human), $computer, $nextstate, - $evalFlag]; + $evalFlag, $relatedVar, $relatedDefault]; return ''; } @@ -1189,7 +1275,8 @@ sub render { if ($self->{'multichoice'}) { $result .= < + SCRIPT } @@ -1266,22 +1354,28 @@ BUTTONS my $id = &new_id(); $result .= "\n \n"; $result .= "[1],"<>&\"'") . "'"; if ($checkedChoices{$choice->[1]}) { - $result .= " checked "; + $result .= " checked='checked' "; } - $result .= qq{id="$id"}; + $result .= qq{id="id$id"}; my $choiceLabel = $choice->[0]; - if ($choice->[4]) { # if we need to evaluate this choice + if ($choice->[3]) { # if we need to evaluate this choice $choiceLabel = "sub { my $helper = shift; my $state = shift;" . $choiceLabel . "}"; $choiceLabel = eval($choiceLabel); $choiceLabel = &$choiceLabel($helper, $self); } - $result .= "/> ".qq{\n"; + $result .= "/> ".qq{"; + if ($choice->[4]) { + $result .=''; + } + $result .= "\n"; } $result .= "\n\n\n"; $result .= $buttons; @@ -1293,7 +1387,7 @@ BUTTONS # given, switch to it sub postprocess { my $self = shift; - my $chosenValue = $ENV{'form.' . $self->{'variable'} . '.forminput'}; + my $chosenValue = $env{'form.' . $self->{'variable'} . '.forminput'}; if (!defined($chosenValue) && !$self->{'allowempty'}) { $self->{ERROR_MSG} = @@ -1315,6 +1409,10 @@ sub postprocess { $helper->changeState($choice->[2]); } } + if ($choice->[4]) { + my $varname = $choice->[4]; + $helper->{'VARS'}->{$varname} = $env{'form.'."$varname.forminput"}; + } } return 1; } @@ -1347,6 +1445,7 @@ no strict; @ISA = ("Apache::lonhelper::element"); use strict; use Apache::lonlocal; +use Apache::lonnet; BEGIN { &Apache::lonhelper::register('Apache::lonhelper::dropdown', @@ -1427,7 +1526,7 @@ sub render { HTML::Entities::encode($choice->[1],"<>&\"'") . "'"; if ($checkedChoices{$choice->[1]}) { - $result .= " selected"; + $result .= " selected='selected' "; } my $choiceLabel = $choice->[0]; if ($choice->[4]) { # if we need to evaluate this choice @@ -1436,7 +1535,7 @@ sub render { $choiceLabel = eval($choiceLabel); $choiceLabel = &$choiceLabel($helper, $self); } - $result .= ">" . &mtn($choiceLabel) . "\n"; + $result .= ">" . &mtn($choiceLabel) . "\n"; } $result .= "\n"; @@ -1447,7 +1546,7 @@ sub render { # given, switch to it sub postprocess { my $self = shift; - my $chosenValue = $ENV{'form.' . $self->{'variable'} . '.forminput'}; + my $chosenValue = $env{'form.' . $self->{'variable'} . '.forminput'}; if (!defined($chosenValue) && !$self->{'allowempty'}) { $self->{ERROR_MSG} = "You must choose one or more choices to" . @@ -1506,7 +1605,7 @@ no strict; @ISA = ("Apache::lonhelper::element"); use strict; use Apache::lonlocal; # A localization nightmare - +use Apache::lonnet; use Time::localtime; BEGIN { @@ -1534,6 +1633,7 @@ sub start_date { $paramHash->{'variable'} = $token->[2]{'variable'}; $helper->declareVar($paramHash->{'variable'}); $paramHash->{'hoursminutes'} = $token->[2]{'hoursminutes'}; + $paramHash->{'anytime'} = $token->[2]{'anytime'}; } sub end_date { @@ -1552,10 +1652,43 @@ sub render { my $var = $self->{'variable'}; my $date; - + + my $time=time; + my ($anytime,$onclick); + + + # first check VARS for a valid new value from the user + # then check DEFAULT_VALUE for a valid default time value + # otherwise pick now as reasonably good time + + if (defined($helper->{VARS}{$var}) + && $helper->{VARS}{$var} > 0) { + $date = localtime($helper->{VARS}{$var}); + } elsif (defined($self->{DEFAULT_VALUE})) { + my $valueFunc = eval($self->{DEFAULT_VALUE}); + die('Error in default value code for variable ' . + $self->{'variable'} . ', Perl said: ' . $@) if $@; + $time = &$valueFunc($helper, $self); + if (lc($time) eq 'anytime') { + $anytime=1; + $date = localtime(time); + $date->min(0); + } elsif (defined($time) && $time ne 0) { + $date = localtime($time); + } else { + # leave date undefined so it'll default to now + } + } + + if (!defined($date)) { + $date = localtime(time); + $date->min(0); + } + + if ($anytime) { + $onclick = "onclick=\"javascript:updateCheck(this.form,'${var}anytime',false)\""; + } # Default date: The current hour. - $date = localtime(); - $date->min(0); if (defined $self->{ERROR_MSG}) { $result .= '' . $self->{ERROR_MSG} . '

'; @@ -1563,10 +1696,10 @@ sub render { # Month my $i; - $result .= "\n"; for ($i = 0; $i < 12; $i++) { if ($i == $date->mon) { - $result .= "\n"; for ($i = 1; $i < 12; $i++) { if ($date->hour == $i) { - $result .= "\n"; + $result .= "\n"; } else { $result .= "\n"; } } - $result .= "\n"; for ($i = 13; $i < 24; $i++) { my $printedHour = $i - 12; if ($date->hour == $i) { - $result .= "\n"; + $result .= "\n"; } else { $result .= "\n"; } @@ -1627,14 +1760,16 @@ sub render { $result .= " :\n"; - $result .= "\n"; + my $selected=0; + for my $i ((0,15,30,45,59,undef,0..59)) { my $printedMinute = $i; - if ($i < 10) { + if (defined($i) && $i < 10) { $printedMinute = "0" . $printedMinute; } - if ($date->min == $i) { - $result .= "