--- loncom/interface/lonhelper.pm 2003/04/11 17:21:18 1.6 +++ loncom/interface/lonhelper.pm 2003/04/11 19:01:46 1.9 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # .helper XML handler to implement the LON-CAPA helper # -# $Id: lonhelper.pm,v 1.6 2003/04/11 17:21:18 bowersj2 Exp $ +# $Id: lonhelper.pm,v 1.9 2003/04/11 19:01:46 bowersj2 Exp $ # # Copyright Michigan State University Board of Trustees # @@ -30,10 +30,6 @@ # (.helper handler # -# FIXME: Change register calls to register with the helper. -# Then have the helper reg and unreg the tags. -# This removes my concerns about breaking other code. - =pod =head1 lonhelper - HTML Helper framework for LON-CAPA @@ -62,8 +58,8 @@ of the helper itself, such as "Parameter =head2 State tags State tags are required to have an attribute "name", which is the symbolic -name of the state and will not be directly seen by the user. The wizard is -required to have one state named "START", which is the state the wizard +name of the state and will not be directly seen by the user. The helper is +required to have one state named "START", which is the state the helper will start with. By convention, this state should clearly describe what the helper will do for the user, and may also include the first information entry the user needs to do for the helper. @@ -95,12 +91,26 @@ use Apache::Constants qw(:common); use Apache::File; use Apache::lonxml; +# Register all the tags with the helper, so the helper can +# push and pop them + +my @helperTags; + +sub register { + my ($namespace, @tags) = @_; + + for my $tag (@tags) { + push @helperTags, [$namespace, $tag]; + } +} + BEGIN { - &Apache::lonxml::register('Apache::lonhelper', - ('helper', 'state')); + Apache::lonxml::register('Apache::lonhelper', + ('helper')); + register('Apache::lonhelper', ('state')); } -# Since all wizards are only three levels deep (wizard tag, state tag, +# Since all helpers are only three levels deep (helper tag, state tag, # substate type), it's easier and more readble to explicitly track # those three things directly, rather then futz with the tag stack # every time. @@ -145,7 +155,7 @@ sub handler { &Apache::lonxml::xmlparse($r, 'helper', $file); $r->print($helper->display()); - return OK; + return OK; } sub start_helper { @@ -154,6 +164,10 @@ sub start_helper { if ($target ne 'helper') { return ''; } + + for my $tagList (@helperTags) { + Apache::lonxml::register($tagList->[0], $tagList->[1]); + } $helper = Apache::lonhelper::helper->new($token->[2]{'title'}); return ''; @@ -165,7 +179,11 @@ sub end_helper { if ($target ne 'helper') { return ''; } - + + for my $tagList (@helperTags) { + Apache::lonxml::deregister($tagList->[0], $tagList->[1]); + } + return ''; } @@ -265,6 +283,10 @@ sub new { $self->{STATES} = {}; $self->{DONE} = 0; + # Used by various helpers for various things; see lonparm.helper + # for an example. + $self->{DATA} = {}; + bless($self, $class); return $self; } @@ -546,8 +568,8 @@ the helper variables, like this: =cut BEGIN { - &Apache::lonxml::register('Apache::lonhelper::element', - ('nextstate')); + &Apache::lonhelper::register('Apache::lonhelper::element', + ('nextstate')); } # Because we use the param hash, this is often a sufficent @@ -637,7 +659,7 @@ transition directly to the state in the This will display the HTML message and transition to the if -given. The HTML will be directly inserted into the wizard, so if you don't +given. The HTML will be directly inserted into the helper, so if you don't want text to run together, you'll need to manually wrap the in

tags, or whatever is appropriate for your HTML. @@ -657,7 +679,7 @@ no strict; use strict; BEGIN { - &Apache::lonxml::register('Apache::lonhelper::message', + &Apache::lonhelper::register('Apache::lonhelper::message', ('message', 'message_text')); } @@ -772,8 +794,6 @@ You can mix and match methods of creatin "push" onto the choice list, rather then wiping it out. (You can even remove choices programmatically, but that would probably be bad form.) -FIXME: Document and implement and in the element package. - =cut no strict; @@ -781,7 +801,7 @@ no strict; use strict; BEGIN { - &Apache::lonxml::register('Apache::lonhelper::choices', + &Apache::lonhelper::register('Apache::lonhelper::choices', ('choice', 'choices')); } @@ -960,7 +980,7 @@ use strict; use Time::localtime; BEGIN { - &Apache::lonxml::register('Apache::lonhelper::date', + &Apache::lonhelper::register('Apache::lonhelper::date', ('date')); } @@ -1182,7 +1202,7 @@ no strict; use strict; BEGIN { - &Apache::lonxml::register('Apache::lonhelper::resource', + &Apache::lonhelper::register('Apache::lonhelper::resource', ('resource', 'filterfunc', 'choicefunc', 'valuefunc')); } @@ -1363,7 +1383,7 @@ use strict; BEGIN { - &Apache::lonxml::register('Apache::lonhelper::student', + &Apache::lonhelper::register('Apache::lonhelper::student', ('student')); } @@ -1527,8 +1547,8 @@ no strict; use strict; BEGIN { - &Apache::lonxml::register('Apache::lonhelper::files', - ('files', 'filechoice', 'filefilter')); + &Apache::lonhelper::register('Apache::lonhelper::files', + ('files', 'filechoice', 'filefilter')); } sub new { @@ -1699,5 +1719,96 @@ sub postprocess { 1; +package Apache::lonhelper::general; + +=pod + +=head2 General-purpose tag: + +The contents of the exec tag are executed as Perl code, not inside a +safe space, so the full range of $ENV and such is available. The code +will be executed as a subroutine wrapped with the following code: + +"sub { my $helper = shift; my $state = shift;" and + +"}" + +The return value is ignored. + +$helper is the helper object. Feel free to add methods to the helper +object to support whatever manipulation you may need to do (for instance, +overriding the form location if the state is the final state; see +lonparm.helper for an example). + +$state is the $paramHash that has currently been generated and may +be manipulated by the code in exec. Note that the $state is not yet +an actual state B, it is just a hash, so do not expect to +be able to call methods on it. + +=cut + +BEGIN { + &Apache::lonhelper::register('Apache::lonhelper::general', + 'exec', 'condition', 'clause'); +} + +sub start_exec { + my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; + + if ($target ne 'helper') { + return ''; + } + + my $code = &Apache::lonxml::get_all_text('/exec', $parser); + + $code = eval ('sub { my $helper = shift; my $state = shift; ' . + $code . "}"); + &$code($helper, $paramHash); +} + +sub end_exec { return ''; } + +=pod + +=head2 General-purpose tag: + +The tag allows you to mask out parts of the helper code +depending on some programatically determined condition. The condition +tag contains a tag which contains perl code that when wrapped +with "sub { my $helper = shift; my $state = shift; " and "}", returns +a true value if the XML in the condition should be evaluated as a normal +part of the helper, or false if it should be completely discarded. + +The tag must be the first sub-tag of the tag or +it will not work as expected. + +=cut + +# The condition tag just functions as a marker, it doesn't have +# to "do" anything. Technically it doesn't even have to be registered +# with the lonxml code, but I leave this here to be explicit about it. +sub start_condition { return ''; } +sub end_condition { return ''; } + +sub start_clause { + my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; + + if ($target ne 'helper') { + return ''; + } + + my $clause = Apache::lonxml::get_all_text('/clause', $parser); + $clause = eval('sub { my $helper = shift; my $state = shift; ' + . $clause . '}'); + if (!&$clause($helper, $paramHash)) { + # Discard all text until the /condition. + &Apache::lonxml::get_all_text('/condition', $parser); + } +} + +sub end_clause { return ''; } + +1; + __END__