--- loncom/interface/lonhelper.pm 2008/12/21 16:24:49 1.166.2.2
+++ loncom/interface/lonhelper.pm 2022/06/27 20:35:51 1.204
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# .helper XML handler to implement the LON-CAPA helper
#
-# $Id: lonhelper.pm,v 1.166.2.2 2008/12/21 16:24:49 raeburn Exp $
+# $Id: lonhelper.pm,v 1.204 2022/06/27 20:35:51 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -64,9 +64,11 @@ messages, resource selections, or date q
The helper tag is required to have one attribute, "title", which is the name
of the helper itself, such as "Parameter helper". The helper tag may optionally
-have a "requiredpriv" attribute, specifying the priviledge a user must have
+have a "requiredpriv" attribute, specifying the privilege a user must have
to use the helper, or get denied access. See loncom/auth/rolesplain.tab for
-useful privs. Default is full access, which is often wrong!
+useful privs. You may add the modifier &S at the end of the three letter priv
+if you want to grant access to users for whom the corresponding privilege is
+section-specific. The default is full access, which is often wrong!
=head2 State tags
@@ -188,6 +190,8 @@ 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
@@ -259,7 +263,7 @@ sub real_handler {
my $uri = shift;
if (!defined($uri)) { $uri = $r->uri(); }
$env{'request.uri'} = $uri;
- my $filename = '/home/httpd/html' . $uri;
+ my $filename = $r->dir_config('lonDocRoot').$uri;
my $fh = Apache::File->new($filename);
my $file;
read $fh, $file, 100000000;
@@ -281,7 +285,8 @@ sub real_handler {
my $allowed = $helper->allowedCheck();
if (!$allowed) {
- $env{'user.error.msg'} = $env{'request.uri'}.':'.$helper->{REQUIRED_PRIV}.
+ my ($priv,$modifier) = split(/\&/,$helper->{REQUIRED_PRIV});
+ $env{'user.error.msg'} = $env{'request.uri'}.':'.$priv.
":0:0:Permission denied to access this helper.";
return HTTP_NOT_ACCEPTABLE;
}
@@ -506,8 +511,13 @@ sub allowedCheck {
if (!defined($self->{REQUIRED_PRIV})) {
return 1;
}
-
- return Apache::lonnet::allowed($self->{REQUIRED_PRIV}, $env{'request.course.id'});
+ my ($priv,$modifier) = split(/\&/,$self->{REQUIRED_PRIV});
+ my $allowed = &Apache::lonnet::allowed($priv,$env{'request.course.id'});
+ if ((!$allowed) && ($modifier eq 'S') && ($env{'request.course.sec'} ne '')) {
+ $allowed = &Apache::lonnet::allowed($priv,$env{'request.course.id'}.'/'.
+ $env{'request.course.sec'});
+ }
+ return $allowed;
}
sub changeState {
@@ -529,7 +539,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();
}
@@ -569,7 +579,7 @@ sub process {
# 4: Render the current state to the screen as an HTML page.
sub display {
my $self = shift;
-
+ my $footer = shift;
my $state = $self->{STATES}{$self->{STATE}};
my $result = "";
@@ -587,82 +597,79 @@ sub display {
&Apache::loncommon::browser_and_searcher_javascript().
"\n".'';
+ # Breadcrumbs
+ my $brcrum = [{'href' => '',
+ 'text' => 'Helper'}];
+ # FIXME: Dynamically add context sensitive breadcrumbs
+ # depending on the caller,
+ # e.g. printing, parametrization, etc.
+ # FIXME: Add breadcrumbs to reflect current helper state
+
$result .= &Apache::loncommon::start_page($self->{TITLE},
- $browser_searcher_js);
-
- my $previous = HTML::Entities::encode(&mt("<- Previous"), '<>&"');
- my $next = HTML::Entities::encode(&mt("Next ->"), '<>&"');
+ $browser_searcher_js,
+ {'bread_crumbs' => $brcrum,});
+
+ my $previous = HTML::Entities::encode(&mt("Back"), '<>&"');
+ my $next = HTML::Entities::encode(&mt("Next"), '<>&"');
# FIXME: This should be parameterized, not concatenated - Jeremy
- if (!$state->overrideForm()) { $result.="
FOOTER
- $result .= &Apache::loncommon::end_page();
+ $result .= $footer.&Apache::loncommon::end_page();
# Handle writing out the vars to the file
my $file = Apache::File->new('>'.$self->{FILENAME});
print $file $self->_varsInFile();
@@ -1477,9 +1484,9 @@ BUTTONS
HTML::Entities::encode($choice->[1],"<>&\"'")
. "'";
if ($checkedChoices{$choice->[1]}) {
- $result .= " checked='checked' ";
+ $result .= " checked='checked'";
}
- $result .= qq{id="id$id"};
+ $result .= qq{ id="id$id"};
my $choiceLabel = $choice->[0];
if ($choice->[3]) { # if we need to evaluate this choice
$choiceLabel = "sub { my $helper = shift; my $state = shift;" .
@@ -1487,7 +1494,7 @@ BUTTONS
$choiceLabel = eval($choiceLabel);
$choiceLabel = &$choiceLabel($helper, $self);
}
- $result .= "/>
".qq{
".qq{
";
if ($choice->[4]) {
$result .='
{VARS}->{$self->{'variable'}} = join('|||', @$chosenValue);
}
@@ -1790,7 +1800,7 @@ sub render {
if (lc($time) eq 'anytime') {
$anytime=1;
$date = &get_date_object(time);
- $date->min(0);
+ $date->set_minute(0);
} elsif (defined($time) && $time ne 0) {
$date = &get_date_object($time);
} else {
@@ -1800,7 +1810,7 @@ sub render {
if (!defined($date)) {
$date = &get_date_object(time);
- $date->min(0);
+ $date->set_minute(0);
}
if ($anytime) {
@@ -1911,7 +1921,13 @@ CHECK
if ($anytime) {
$result.=' checked="checked" '
}
- $result.="name='${var}anytime'/>".&mt('Any time').''
+ my $anytimetext = &mt('Any time');
+ if (($var eq 'startreserve') || ($var eq 'endreserve')) {
+ $anytimetext = &mt('Any time before slot starts');
+ } elsif (($var eq 'startunique') || ($var eq 'endunique')) {
+ $anytimetext = &mt('No restriction on uniqueness');
+ }
+ $result.="name='${var}anytime'/>".$anytimetext.''
}
return $result;
@@ -2031,7 +2047,9 @@ be filtered out. The 'addstatus' attribu
and long status display columns to the display. The 'addparts'
attribute will add in a part selector beside problems that have more
than 1 part. The 'includecourse' attribute if true, will include
-the toplevel default.sequence in the results.
+the toplevel default.sequence in the results. The 'modalLink' attribute,
+if true, will cause links to be launched as modal pop-ups, instead of
+replacing the resource selection listing, currently being displayed.
=head3 SUB-TAGS
@@ -2064,6 +2082,49 @@ the toplevel default.sequence in the res
evaluated with "sub { my $helper = shift; my $state = shift;" and
"}", with the return value used as the mapurl.
+=item * : Allows you to add optional elements to the
+ resource chooser currently these can be a checkbox, or a text entry
+ or hidden (see the 'type' attribute below).
+ the following attributes are supported by this tag:
+
+=over 4
+
+=item * type=control-type : determines the type of control displayed.
+ This can be one of the following types: 'checkbox' provides a true/false
+ checkbox. 'text' provides a text entry control. 'hidden' provides a
+ hidden form element that returns the name of the resource for each
+ element of the text box.
+
+=item * text=header-text : provides column header text for the option.
+
+=item * variable=helpervar : provides a helper variable to contain the
+ value of the input control for each resource. In general, the result
+ will be a set of values separated by ||| for the checkbox the value between
+ the |||'s will either be empty, if the box is not checked, or the resource
+ name if checked. For the text entry, the values will be the text in the
+ text box. This could be empty. Hidden elements unconditionally provide
+ the resource name for each row of the chooser and allow you to therefore
+ correlate text entries to their resources.
+ The helper variable can be initialized by the user code to pre-load values
+ into the controls:
+
+=over 4
+
+
+=item * Preloading checkboxes : Set the helper variable to the value you
+ would have gotten from the control if it had been manually set as desired.
+
+=item * Preloading text entries : Set the helper variable to triple pipe
+ separated values where each value is of the form resource-name=value
+
+=item * Preloading hidden fields : These cannot be pre-loaded and will always
+ be pipe separated resource names.
+
+=back
+
+
+=back
+
=back
=cut
@@ -2100,6 +2161,9 @@ sub start_resource {
$paramHash->{'toponly'} = $token->[2]{'toponly'};
$paramHash->{'addstatus'} = $token->[2]{'addstatus'};
$paramHash->{'addparts'} = $token->[2]{'addparts'};
+ $paramHash->{'modalLink'} = $token->[2]{'modallink'};
+ $paramHash->{'nocurrloc'} = $token->[2]{'nocurrloc'};
+ $paramHash->{'suppressNavmap'} = $token->[2]{'suppressNavmap'};
if ($paramHash->{'addparts'}) {
$helper->declareVar($paramHash->{'variable'}.'_part');
}
@@ -2193,20 +2257,42 @@ sub start_option {
if (!defined($paramHash->{OPTION_TEXTS})) {
$paramHash->{OPTION_TEXTS} = [ ];
$paramHash->{OPTION_VARS} = [ ];
+ $paramHash->{OPTION_TYPES} = [ ];
}
+ # We can have an attribute: type which can have the
+ # values: "checkbox" or "text" which defaults to
+ # checkbox allowing us to change the type of input
+ # for the option:
+ #
+ my $input_widget_type = 'checkbox';
+ if(defined($token->[2]{'type'})) {
+ my $widget_type = $token->[2]{'type'};
+ if ($widget_type eq 'text') { # only accept legal alternatives
+ $input_widget_type = $widget_type; # Illegals are checks.
+ } elsif ($widget_type eq 'hidden') {
+ $input_widget_type = $widget_type;
+ }
+ }
+
# OPTION_TEXTS is a list of the text attribute
# values used to create column headings.
# OPTION_VARS is a list of the variable names, used to create the checkbox
# inputs.
+ # OPTION_TYPES is a list of the option types:
+ #
# We're ok with empty elements. as place holders
# Although the 'variable' element should really exist.
#
+
my $option_texts = $paramHash->{OPTION_TEXTS};
my $option_vars = $paramHash->{OPTION_VARS};
+ my $option_types = $paramHash->{OPTION_TYPES};
push(@$option_texts, $token->[2]{'text'});
push(@$option_vars, $token->[2]{'variable'});
+ push(@$option_types, $input_widget_type);
+
# Need to create and declare the option variables as well to make them
# persistent.
@@ -2282,7 +2368,9 @@ BUTTONS
my $multichoice = $self->{'multichoice'};
my $option_vars = $self->{OPTION_VARS};
my $option_texts = $self->{OPTION_TEXTS};
+ my $option_types = $self->{OPTION_TYPES};
my $addparts = $self->{'addparts'};
+ my $modalLink = $self->{'modalLink'};
my $headings_done = 0;
# Evaluate the map url as needed
@@ -2322,7 +2410,7 @@ BUTTONS
$result .= "
$text
";
}
}
- $result .= "
Select
";
+ $result .= '
'.&Apache::lonlocal::mt('Select').'
';
$result .= "
"; # Close off the extra row and start a new one.
$headings_done = 1;
}
@@ -2340,17 +2428,52 @@ BUTTONS
my $resource_name =
HTML::Entities::encode($raw_name,"<>&\"'");
if($option_vars) {
+ my $option_num = 0;
foreach my $option_var (@$option_vars) {
+ my $option_type = $option_types->[$option_num];
+ $option_num++;
my $var_value = "\|\|\|" . $helper->{VARS}->{$option_var} .
"\|\|\|";
my $checked ="";
if($var_value =~ /\Q|||$raw_name|||\E/) {
$checked = "checked='checked'";
}
- $col .=
- "
";
+ if ($option_type eq 'text') {
+ #
+ # For text's the variable value is a ||| separated set of
+ # resource_name=value
+ #
+ my @values = split(/\|\|\|/, $helper->{VARS}->{$option_var});
+
+ # Normal practice would be to toss this in a hash but
+ # the only thing that saves is the compare in the loop
+ # below and for all but one case we'll break out of the loop
+ # before it completes.
+
+ my $text_value = ''; # In case there's no match.
+ foreach my $value (@values) {
+ my ($res, $skip) = split(/=/, $value);
+ if($res eq $resource_name) {
+ $text_value = $skip;
+ last;
+ }
+ }
+ # TODO: add an attribute to