--- loncom/interface/courseprefs.pm 2022/07/01 01:05:04 1.112
+++ loncom/interface/courseprefs.pm 2023/12/13 22:12:17 1.128
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Handler to set configuration settings for a course
#
-# $Id: courseprefs.pm,v 1.112 2022/07/01 01:05:04 raeburn Exp $
+# $Id: courseprefs.pm,v 1.128 2023/12/13 22:12:17 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -116,7 +116,7 @@ This module is used for configuration of
=item item_table_row_end()
-=item yes_no_radio()
+=item yesno_radio()
=item select_from_options()
@@ -225,6 +225,7 @@ use Apache::courseclassifier;
use Apache::lonlocal;
use LONCAPA qw(:DEFAULT :match);
use Crypt::CBC;
+use Time::HiRes qw( sleep );
my $registered_cleanup;
my $modified_courses;
@@ -293,7 +294,7 @@ sub handler {
excc => 'Exclude from community catalog',
clon => 'Users allowed to clone community',
rept => 'Replacement titles for standard community roles',
- time => 'Timezone where the community is located',
+ time => 'Time Zone where the community is located',
date => 'Locale used for community calendar',
coco => 'Community Content',
copo => 'Community Policy',
@@ -315,14 +316,14 @@ sub handler {
idnu => 'Course ID or number',
unco => 'Unique code',
desc => 'Course Description',
- cred => 'Student credits',
+ cred => 'Student credits',
ownr => 'Course Owner',
cown => 'Course Co-owners',
catg => 'Categorize course',
excc => 'Exclude from course catalog',
clon => 'Users allowed to clone course',
rept => 'Replacement titles for standard course roles',
- time => 'Timezone in which the course takes place',
+ time => 'Time Zone in which the course takes place',
date => 'Locale used for course calendar',
coco => 'Course Content',
copo => 'Course Policy',
@@ -372,6 +373,8 @@ sub handler {
my %values=&Apache::lonnet::dump('environment',$cdom,$cnum);
my %linkprot=&Apache::lonnet::dump('lti',$cdom,$cnum,undef,undef,undef,1);
my %ltienc = &Apache::lonnet::dump('nohist_ltienc',$cdom,$cnum,undef,undef,undef,1);
+ my %ltitools = &Apache::lonnet::dump('ltitools',$cdom,$cnum,undef,undef,undef,1);
+ my %ltitoolsenc = &Apache::lonnet::dump('nohist_toolsenc',$cdom,$cnum,undef,undef,undef,1);
foreach my $id (keys(%linkprot)) {
if (ref($linkprot{$id}) eq 'HASH') {
if (ref($ltienc{$id}) eq 'HASH') {
@@ -389,11 +392,27 @@ sub handler {
if ($linkprot{'lock'}) {
delete($linkprot{'lock'});
}
+ foreach my $id (keys(%ltitools)) {
+ if (ref($ltitools{$id}) eq 'HASH') {
+ if (ref($ltitoolsenc{$id}) eq 'HASH') {
+ $values{'ltitools'}{$id} = { %{$ltitools{$id}}, %{$ltitoolsenc{$id}} };
+ } else {
+ $values{'ltitools'}{$id} = $ltitools{$id};
+ }
+ }
+ unless ($phase eq 'process') {
+ if (ref($values{'ltitools'}{$id}) eq 'HASH') {
+ delete($values{'ltitools'}{$id}{'secret'});
+ }
+ }
+ }
+ if ($ltitools{'lock'}) {
+ delete($ltitools{'lock'});
+ }
my @prefs_order = ('courseinfo','localization','feedback','discussion',
'classlists','appearance','grading','printouts',
- 'menuitems','linkprot','spreadsheet','bridgetasks',
- 'lti','other');
-
+ 'menuitems','ltitools','linkprot','spreadsheet',
+ 'bridgetasks','lti','other');
my %prefs = (
'courseinfo' =>
{ text => $lt{'gens'},
@@ -492,7 +511,8 @@ sub handler {
help => 'Course_Prefs_Display',
ordered => ['default_xml_style','pageseparators',
'disable_receipt_display','texengine',
- 'tthoptions','uselcmath','usejsme','inline_chem'],
+ 'tthoptions','uselcmath','usejsme',
+ 'inline_chem','extresource'],
itemtext => {
default_xml_style => 'Default XML style file',
pageseparators => 'Visibly Separate Items on Pages',
@@ -502,6 +522,7 @@ sub handler {
uselcmath => 'Student formula entry uses inline preview, not DragMath pop-up',
usejsme => 'Molecule editor uses JSME (HTML5) in place of JME (Java)',
inline_chem => 'Chemical reaction response uses inline preview, not pop-up',
+ extresource => 'Display of external resources',
},
},
'grading' =>
@@ -591,6 +612,14 @@ sub handler {
col2 => 'Settings',
}],
},
+ 'ltitools' =>
+ {
+ text => 'External tools',
+ help => 'Course_Prefs_ExternalTools',
+ header => [{col1 => 'Item',
+ col2 => 'Settings',
+ }],
+ },
'other' =>
{ text => 'Other settings',
help => 'Course_Prefs_Other',
@@ -665,6 +694,8 @@ sub get_allitems {
if ($item eq 'feedback') {
push(@allitems,(map { $_.'.text'; } @{$prefs{$item}{'ordered'}}));
}
+ } elsif (($item eq 'linkprot') || ($item eq 'ltitools')) {
+ push(@allitems,$item);
}
}
}
@@ -791,13 +822,19 @@ sub print_config_box {
} elsif ($action eq 'appearance') {
$output .= &print_appearance($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype,$noedit);
} elsif ($action eq 'grading') {
- $output .= &print_grading($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype,$noedit);
+ $output .= &print_grading($cdom,$cnum,$settings,$ordered,$itemtext,\$rowtotal,$crstype,$noedit);
} elsif ($action eq 'printouts') {
$output .= &print_printouts($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype,$noedit);
} elsif ($action eq 'spreadsheet') {
$output .= &print_spreadsheet($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype,$noedit);
} elsif ($action eq 'bridgetasks') {
$output .= &print_bridgetasks($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype,$noedit);
+ } elsif ($action eq 'ltitools') {
+ my $currtools = {};
+ if ((ref($settings) eq 'HASH') && (ref($settings->{'ltitools'}))) {
+ $currtools = $settings->{'ltitools'};
+ }
+ $output .= &print_ltitools($cdom,$cnum,$currtools,\$rowtotal,$crstype,$noedit,'course');
} elsif ($action eq 'lti') {
$output .= &print_lti($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype,$noedit);
} elsif ($action eq 'menuitems') {
@@ -834,7 +871,7 @@ sub process_changes {
}
}
}
- } elsif ($action eq 'linkprot') {
+ } elsif (($action eq 'linkprot') || ($action eq 'ltitools')) {
if (ref($values->{$action}) eq 'HASH') {
foreach my $id (keys(%{$values->{$action}})) {
if ($id =~ /^\d+$/) {
@@ -843,8 +880,8 @@ sub process_changes {
}
}
@ordered = sort { $a <=> $b } @ordered;
- if (($env{'form.linkprot_add'}) && ($env{'form.linkprot_maxnum'} =~ /^\d+$/)) {
- push(@ordered,$env{'form.linkprot_maxnum'});
+ if (($env{'form.'.$action.'_add'}) && ($env{'form.'.$action.'_maxnum'} =~ /^\d+$/)) {
+ push(@ordered,$env{'form.'.$action.'_maxnum'});
}
} elsif (ref($item->{'ordered'}) eq 'ARRAY') {
if ($action eq 'courseinfo') {
@@ -987,6 +1024,12 @@ sub process_changes {
if (ref($values) eq 'HASH') {
$errors = &process_linkprot($cdom,$cnum,$values->{$action},$changes,'course',$lastactref);
}
+ } elsif ($action eq 'ltitools') {
+ if (ref($values) eq 'HASH') {
+ my $switchserver = &check_switchserver($cdom,$cnum,'course','/adm/courseprefs');
+ $errors = &process_ltitools('',$cdom,$cnum,$values->{$action},$changes,'course',$lastactref,
+ 'ok','','ok');
+ }
} else {
foreach my $entry (@ordered) {
if ($entry eq 'cloners') {
@@ -1296,14 +1339,14 @@ sub process_changes {
my ($classorder,$classtitles) = &discussion_vote_classes();
my $fontchange = 0;
foreach my $class (@{$classorder}) {
- my $ext_entry = $entry.'_'.$class;
+ my $ext_entry = $entry.'_'.$class;
my $size = $env{'form.'.$ext_entry.'_size'};
my $unit = $env{'form.'.$ext_entry.'_unit'};
my $weight = $env{'form.'.$ext_entry.'_weight'};
my $style = $env{'form.'.$ext_entry.'_style'};
my $other = $env{'form.'.$ext_entry.'_other'};
$size =~ s/,//g;
- $unit =~ s/,//g;
+ $unit =~ s/,//g;
$weight =~ s/,//g;
$style =~ s/,//g;
$other =~ s/[^\w;:\s\-\%.]//g;
@@ -1311,7 +1354,7 @@ sub process_changes {
$newvalues{$ext_entry} = join(',',($size.$unit,$weight,$style,$other));
my $current = $values->{$ext_entry};
if ($values->{$ext_entry} eq '') {
- $current = ',,,';
+ $current = ',,,';
}
if ($newvalues{$ext_entry} ne $current) {
$changes->{$ext_entry} = $newvalues{$ext_entry};
@@ -1320,7 +1363,7 @@ sub process_changes {
}
if ($fontchange) {
$changes->{$entry} = 1;
- }
+ }
} elsif ($entry eq 'nothideprivileged') {
my @curr_nothide;
my @new_nothide;
@@ -1395,7 +1438,7 @@ sub process_changes {
my $newtext = $maxnum-1;
$newhdr[$env{'form.printfmthdr_pos_'.$newtext}] = $env{'form.printfmthdr_text_'.$newtext};
$newvalues{$entry} = join('',@newhdr);
- } elsif (($entry eq 'languages') ||
+ } elsif (($entry eq 'languages') ||
($entry eq 'checkforpriv')) {
my $settings;
my $total = $env{'form.'.$entry.'_total'};
@@ -1411,7 +1454,7 @@ sub process_changes {
}
if ($env{'form.'.$entry.'_'.$total} ne '') {
my $new = $env{'form.'.$entry.'_'.$total};
- if ($entry eq 'languages') {
+ if ($entry eq 'languages') {
my %langchoices = &get_lang_choices();
if ($langchoices{$new}) {
$settings .= $new;
@@ -1464,10 +1507,81 @@ sub process_changes {
$newvalues{$entry} = '';
}
}
+ } elsif ($entry eq 'extresource') {
+ if ($env{'form.'.$entry} =~ /^iframe|tab|window$/) {
+ $newvalues{$entry} = $env{'form.'.$entry};
+ if ($env{'form.'.$entry} ne 'iframe') {
+ if ($env{'form.extwintabreuse'}) {
+ $newvalues{$entry} .= ':1';
+ } else {
+ $newvalues{$entry} .= ':0';
+ }
+ if ($env{'form.'.$entry} eq 'window') {
+ foreach my $dim ('width','height') {
+ $env{'form.extreswin'.$dim} =~ s/^\s+|\s+$//g;
+ if ($env{'form.extreswin'.$dim} =~ /^\d+$/) {
+ $newvalues{$entry} .= ':'.$env{'form.extreswin'.$dim};
+ } else {
+ $newvalues{$entry} .= ':';
+ }
+ }
+ }
+ }
+ }
+ unless (($newvalues{$entry} eq 'iframe') && ($values->{$entry} eq '')) {
+ if ($newvalues{$entry} ne $values->{$entry}) {
+ $changes->{$entry} = $newvalues{$entry};
+ }
+ }
+ } elsif ($entry eq 'timezone') {
+ if ($env{'form.'.$entry}) {
+ $newvalues{$entry} = $env{'form.'.$entry};
+ if ($newvalues{$entry} ne $values->{$entry}) {
+ $changes->{$entry} = $newvalues{$entry};
+ }
+ if ($env{'form.tzover'}) {
+ $newvalues{'tzover'} = $env{'form.tzover'};
+ if ($newvalues{'tzover'} ne $values->{'tzover'}) {
+ $changes->{'tzover'} = $newvalues{'tzover'};
+ }
+ } elsif ($values->{'tzover'}) {
+ $changes->{'tzover'} = '';
+ }
+ } elsif ($values->{$entry}) {
+ $changes->{$entry} = '';
+ }
+ } elsif ($entry eq 'grading') {
+ if ($env{'form.'.$entry} eq 'standard') {
+ if ($env{'form.hidetotals'}) {
+ my %sections = &Apache::loncommon::get_sections($cdom,$cnum);
+ if (keys(%sections)) {
+ my @secs = &Apache::loncommon::get_env_multiple('form.hidetotals_sections');
+ if (grep(/^all$/,@secs)) {
+ $newvalues{'hidetotals'} = 'all';
+ } elsif (@secs) {
+ $newvalues{'hidetotals'} = '';
+ foreach my $sec (sort {$a <=> $b} @secs) {
+ if (exists($sections{$sec})) {
+ $newvalues{'hidetotals'} .= $sec.','
+ }
+ }
+ $newvalues{'hidetotals'} =~ s/,$//;
+ }
+ } else {
+ $newvalues{'hidetotals'} = 'all';
+ }
+ }
+ }
+ if ($newvalues{'hidetotals'} ne $values->{'hidetotals'}) {
+ $changes->{'hidetotals'} = $newvalues{'hidetotals'};
+ $changes->{'grading'} = $env{'form.'.$entry};
+ }
+ $newvalues{$entry} = $env{'form.'.$entry};
} else {
$newvalues{$entry} = $env{'form.'.$entry};
}
- unless (($entry eq 'co-owners') || ($entry eq 'discussion_post_fonts')) {
+ unless (($entry eq 'co-owners') || ($entry eq 'discussion_post_fonts') ||
+ ($entry eq 'extresource') || ($entry eq 'timezone')) {
if ($newvalues{$entry} ne $values->{$entry}) {
$changes->{$entry} = $newvalues{$entry};
}
@@ -1482,7 +1596,7 @@ sub process_changes {
sub process_linkprot {
my ($cdom,$cnum,$values,$changes,$context,$lastactref) = @_;
- my ($home,$dest,$ltiauth,$privkey,$privnum,$cipher,$errors,%linkprot);
+ my ($dest,$ltiauth,$privnum,$cipher,$errors,%linkprot);
if (ref($values) eq 'HASH') {
foreach my $id (keys(%{$values})) {
if ($id =~ /^\d+$/) {
@@ -1492,31 +1606,7 @@ sub process_linkprot {
}
}
}
- my %domdefs = &Apache::lonnet::get_domain_defaults($cdom);
- my @ids=&Apache::lonnet::current_machine_ids();
- if ($context eq 'domain') {
- $home = &Apache::lonnet::domain($cdom,'primary');
- } else {
- $home = &Apache::lonnet::homeserver($cnum,$cdom);
- }
- if ((($context eq 'domain') && ($domdefs{'linkprotenc_dom'})) ||
- (($context eq 'course') && ($domdefs{'linkprotenc_crs'}))) {
- unless (($home eq 'no_host') || ($home eq '')) {
- if (grep(/^\Q$home\E$/,@ids)) {
- if (ref($domdefs{'privhosts'}) eq 'ARRAY') {
- if (grep(/^\Q$home\E$/,@{$domdefs{'privhosts'}})) {
- my %privhash = &Apache::lonnet::restore_dom('lti','private',$cdom,$home,1);
- $privkey = $privhash{'key'};
- $privnum = $privhash{'version'};
- if (($privnum) && ($privkey ne '')) {
- $cipher = Crypt::CBC->new({'key' => $privkey,
- 'cipher' => 'DES'});
- }
- }
- }
- }
- }
- }
+ ($cipher,$privnum) = &get_credentials($cdom,$cnum,'lti',$context);
if ($context eq 'domain') {
$dest = '/adm/domainprefs';
$ltiauth = 1;
@@ -1600,15 +1690,32 @@ sub process_linkprot {
} elsif (exists($env{$urlparamname})) {
$env{$urlparamname} = '';
}
+ my $passback = 'form.linkprot_passback_'.$idx;
+ my $passbackparamname = 'form.linkprot_passbackformat_'.$idx;
+ if ($env{$passback} == 1) {
+ unless ($env{$passbackparamname} =~ /^1\.(0|1)$/) {
+ $env{$passbackparamname} = '';
+ }
+ } elsif (exists($env{$passbackparamname})) {
+ $env{$passbackparamname} = '';
+ }
unless ($idx eq 'add') {
if ((!$current{'returnurl'} && ($env{$urlparamname} ne '')) ||
($current{'returnurl'} && ($env{$urlparamname} eq ''))) {
$haschanges{$itemid} = 1;
}
+ if ((!$current{'passback'} && ($env{$passbackparamname} ne '')) ||
+ ($current{'passback'} && ($env{$passbackparamname} eq ''))) {
+ $haschanges{$itemid} = 1;
+ }
}
if ($env{$urlparamname} ne '') {
$linkprot{$itemid}{'returnurl'} = $env{$urlparamname};
}
+ if ($env{$passbackparamname} ne '') {
+ $linkprot{$itemid}{'passback'} = 1;
+ $linkprot{$itemid}{'passbackformat'} = $env{$passbackparamname};
+ }
if ($ltiauth) {
my $reqitem = 'form.linkprot_requser_'.$idx;
$env{$reqitem} =~ s/(`)/'/g;
@@ -1719,7 +1826,7 @@ sub get_linkprot_id {
$tries ++;
sleep (0.1);
if ($context eq 'domain') {
- $gotlock = &Apache::lonnet::newput_dom('linkprot',$lockhash,$cdom);
+ $gotlock = &Apache::lonnet::newput_dom('linkprot',$lockhash,$cdom);
} else {
$gotlock = &Apache::lonnet::newput('lti',$lockhash,$cdom,$cnum);
}
@@ -1757,7 +1864,7 @@ sub get_linkprot_id {
$error = 'nonumber';
}
}
- my $dellockoutcome;
+ my $dellockoutcome;
if ($context eq 'domain') {
$dellockoutcome = &Apache::lonnet::del_dom('linkprot',['lock'],$cdom);
} else {
@@ -1769,6 +1876,604 @@ sub get_linkprot_id {
return ($id,$error);
}
+sub get_credentials {
+ my ($cdom,$cnum,$type,$context) = @_;
+ my ($cipher,$privnum,$home);
+ my %domdefs = &Apache::lonnet::get_domain_defaults($cdom);
+ my @ids=&Apache::lonnet::current_machine_ids();
+ if ($context eq 'domain') {
+ $home = &Apache::lonnet::domain($cdom,'primary');
+ } else {
+ $home = &Apache::lonnet::homeserver($cnum,$cdom);
+ }
+ my ($hostskey,$domkey,$crskey);
+ if ($type eq 'ltitools') {
+ $hostskey = 'toolprivhosts';
+ $domkey = 'toolenc_dom';
+ $crskey = 'toolenc_crs';
+ } else {
+ $hostskey = 'ltiprivhosts';
+ $domkey = 'linkprotenc_dom';
+ $crskey = 'linkprotenc_crs';
+ }
+ if ((($context eq 'domain') && ($domdefs{$domkey})) ||
+ (($context eq 'course') && ($domdefs{$crskey}))) {
+ unless (($home eq 'no_host') || ($home eq '')) {
+ if (grep(/^\Q$home\E$/,@ids)) {
+ if (ref($domdefs{$hostskey}) eq 'ARRAY') {
+ if (grep(/^\Q$home\E$/,@{$domdefs{$hostskey}})) {
+ my %privhash = &Apache::lonnet::restore_dom($type,'private',$cdom,$home,1);
+ my $privkey = $privhash{'key'};
+ $privnum = $privhash{'version'};
+ if (($privnum) && ($privkey ne '')) {
+ $cipher = Crypt::CBC->new({'key' => $privkey,
+ 'cipher' => 'DES'});
+ }
+ }
+ }
+ }
+ }
+ }
+ return ($cipher,$privnum);
+}
+
+sub process_ltitools {
+ my ($r,$cdom,$cnum,$values,$changes,$context,$lastactref,$configuserok,$lonhost,
+ $author_ok,$confname) = @_;
+ my (%currconfig,$newid,@allpos,%changes,%ltitools,$errors);
+
+ my (%posslti,%possfield);
+ my @courseroles = ('cc','in','ta','ep','st');
+ my @ltiroles = qw(Instructor ContentDeveloper TeachingAssistant Learner);
+ map { $posslti{$_} = 1; } @ltiroles;
+ my @allfields = ('fullname','firstname','lastname','email','user','roles');
+ map { $possfield{$_} = 1; } @allfields;
+
+ my ($dest,$privnum,$cipher);
+
+ ($cipher,$privnum) = &get_credentials($cdom,$cnum,'ltitools',$context);
+ if ($context eq 'domain') {
+ $dest = '/adm/domainprefs';
+ } else {
+ $dest = '/adm/courseprefs';
+ }
+ my $switchserver = &check_switchserver($cdom,$cnum,$context,$dest);
+
+ my (@allpos,@items,%deletions,%itemids,%haschanges);
+ if ($env{'form.ltitools_add'}) {
+ my $title = $env{'form.ltitools_add_title'};
+ $title =~ s/(`)/'/g;
+ my ($newid,$error) = &Apache::lonnet::get_ltitools_id($context,$cdom,$cnum,$title);
+ if ($newid) {
+ my $position = $env{'form.ltitools_add_pos'};
+ $position =~ s/\D+//g;
+ if ($position ne '') {
+ $allpos[$position] = $newid;
+ }
+ $haschanges{$newid} = 1;
+ foreach my $item ('title','url','lifetime') {
+ $env{'form.ltitools_add_'.$item} =~ s/(`)/'/g;
+ if ($item eq 'lifetime') {
+ $env{'form.ltitools_add_'.$item} =~ s/[^\d.]//g;
+ }
+ if ($env{'form.ltitools_add_'.$item}) {
+ $ltitools{$newid}{$item} = $env{'form.ltitools_add_'.$item};
+ }
+ }
+ if ($env{'form.ltitools_add_version'} eq 'LTI-1p0') {
+ $ltitools{$newid}{'version'} = $env{'form.ltitools_add_version'};
+ }
+ if ($env{'form.ltitools_add_msgtype'} eq 'basic-lti-launch-request') {
+ $ltitools{$newid}{'msgtype'} = $env{'form.ltitools_add_msgtype'};
+ }
+ if ($env{'form.ltitools_add_sigmethod'} eq 'HMAC-SHA256') {
+ $ltitools{$newid}{'sigmethod'} = $env{'form.ltitools_add_sigmethod'};
+ } else {
+ $ltitools{$newid}{'sigmethod'} = 'HMAC-SHA1';
+ }
+ foreach my $item ('width','height','linktext','explanation') {
+ $env{'form.ltitools_add_'.$item} =~ s/^\s+//;
+ $env{'form.ltitools_add_'.$item} =~ s/\s+$//;
+ if (($item eq 'width') || ($item eq 'height')) {
+ if ($env{'form.ltitools_add_'.$item} =~ /^\d+$/) {
+ $ltitools{$newid}{'display'}{$item} = $env{'form.ltitools_add_'.$item};
+ }
+ } else {
+ if ($env{'form.ltitools_add_'.$item} ne '') {
+ $ltitools{$newid}{'display'}{$item} = $env{'form.ltitools_add_'.$item};
+ }
+ }
+ }
+ if ($env{'form.ltitools_add_target'} eq 'window') {
+ $ltitools{$newid}{'display'}{'target'} = $env{'form.ltitools_add_target'};
+ } elsif ($env{'form.ltitools_add_target'} eq 'tab') {
+ $ltitools{$newid}{'display'}{'target'} = $env{'form.ltitools_add_target'};
+ } else {
+ $ltitools{$newid}{'display'}{'target'} = 'iframe';
+ }
+ foreach my $item ('passback','roster') {
+ if ($env{'form.ltitools_'.$item.'_add'}) {
+ $ltitools{$newid}{$item} = 1;
+ if ($env{'form.ltitools_'.$item.'valid_add'} ne '') {
+ my $lifetime = $env{'form.ltitools_'.$item.'valid_add'};
+ $lifetime =~ s/^\s+|\s+$//g;
+ if ($lifetime =~ /^\d+\.?\d*$/) {
+ $ltitools{$newid}{$item.'valid'} = $lifetime;
+ }
+ }
+ }
+ }
+ if ($env{'form.ltitools_add_image.filename'} ne '') {
+ my ($imageurl,$error) =
+ &process_ltitools_image($r,$context,$cdom,$cnum,$confname,'ltitools_add_image',
+ $newid,$configuserok,$lonhost,$author_ok);
+ if ($imageurl) {
+ $ltitools{$newid}{'image'} = $imageurl;
+ }
+ if ($error) {
+ &Apache::lonnet::logthis($error);
+ $errors .= '
'.$error.'';
+ }
+ }
+ my @fields = &Apache::loncommon::get_env_multiple('form.ltitools_add_fields');
+ foreach my $field (@fields) {
+ if ($possfield{$field}) {
+ if ($field eq 'roles') {
+ foreach my $role (@courseroles) {
+ my $choice = $env{'form.ltitools_add_roles_'.$role};
+ if (($choice ne '') && ($posslti{$choice})) {
+ $ltitools{$newid}{'roles'}{$role} = $choice;
+ if ($role eq 'cc') {
+ $ltitools{$newid}{'roles'}{'co'} = $choice;
+ }
+ }
+ }
+ } else {
+ $ltitools{$newid}{'fields'}{$field} = 1;
+ }
+ }
+ }
+ if (ref($ltitools{$newid}{'fields'}) eq 'HASH') {
+ if ($ltitools{$newid}{'fields'}{'user'}) {
+ if ($env{'form.ltitools_add_userincdom'}) {
+ $ltitools{$newid}{'incdom'} = 1;
+ }
+ }
+ }
+ my @courseconfig = &Apache::loncommon::get_env_multiple('form.ltitools_add_courseconfig');
+ foreach my $item (@courseconfig) {
+ $ltitools{$newid}{'crsconf'}{$item} = 1;
+ }
+ if ($env{'form.ltitools_add_custom'}) {
+ my $name = $env{'form.ltitools_add_custom_name'};
+ my $value = $env{'form.ltitools_add_custom_value'};
+ $value =~ s/(`)/'/g;
+ $name =~ s/(`)/'/g;
+ $ltitools{$newid}{'custom'}{$name} = $value;
+ }
+ unless ($switchserver) {
+ my $keyitem = 'form.ltitools_add_key';
+ $env{$keyitem} =~ s/(`)/'/g;
+ if ($env{$keyitem} ne '') {
+ $ltitools{$newid}{'key'} = $env{$keyitem};
+ }
+ my $secretitem = 'form.ltitools_secret_add';
+ $env{$secretitem} =~ s/(`)/'/g;
+ if ($env{$secretitem} ne '') {
+ if ($privnum && $cipher) {
+ $ltitools{$newid}{'secret'} = $cipher->encrypt_hex($env{$secretitem});
+ $ltitools{$newid}{'cipher'} = $privnum;
+ } else {
+ $ltitools{$newid}{'secret'} = $env{$secretitem};
+ }
+ }
+ }
+ } else {
+ $errors .= ''.
+ &mt('Failed to acquire unique ID for new external tool').
+ '';
+ }
+ }
+ if (ref($values) eq 'HASH') {
+ my %deletions;
+ my @todelete = &Apache::loncommon::get_env_multiple('form.ltitools_del');
+ if (@todelete) {
+ map { $deletions{$_} = 1; } @todelete;
+ }
+ my %customadds;
+ my @newcustom = &Apache::loncommon::get_env_multiple('form.ltitools_customadd');
+ if (@newcustom) {
+ map { $customadds{$_} = 1; } @newcustom;
+ }
+ my %imgdeletions;
+ my @todeleteimages = &Apache::loncommon::get_env_multiple('form.ltitools_image_del');
+ if (@todeleteimages) {
+ map { $imgdeletions{$_} = 1; } @todeleteimages;
+ }
+ my $maxnum = $env{'form.ltitools_maxnum'};
+ for (my $i=0; $i<=$maxnum; $i++) {
+ my $itemid = $env{'form.ltitools_id_'.$i};
+ $itemid =~ s/\D+//g;
+ if (ref($values->{$itemid}) eq 'HASH') {
+ if ($deletions{$itemid}) {
+ if ($values->{$itemid}{'image'}) {
+ #FIXME need to obsolete item in RES space
+ }
+ $haschanges{$itemid} = $values->{$itemid}{'title'};
+ next;
+ } else {
+ my $newpos = $env{'form.ltitools_'.$itemid};
+ $newpos =~ s/\D+//g;
+ foreach my $item ('title','url','lifetime') {
+ $ltitools{$itemid}{$item} = $env{'form.ltitools_'.$item.'_'.$i};
+ if ($values->{$itemid}{$item} ne $ltitools{$itemid}{$item}) {
+ $haschanges{$itemid} = 1;
+ }
+ }
+ if ($env{'form.ltitools_version_'.$i} eq 'LTI-1p0') {
+ $ltitools{$itemid}{'version'} = $env{'form.ltitools_version_'.$i};
+ }
+ if ($env{'form.ltitools_msgtype_'.$i} eq 'basic-lti-launch-request') {
+ $ltitools{$itemid}{'msgtype'} = $env{'form.ltitools_msgtype_'.$i};
+ }
+ if ($env{'form.ltitools_sigmethod_'.$i} eq 'HMAC-SHA256') {
+ $ltitools{$itemid}{'sigmethod'} = $env{'form.ltitools_sigmethod_'.$i};
+ } else {
+ $ltitools{$itemid}{'sigmethod'} = 'HMAC-SHA1';
+ }
+ if ($values->{$itemid}{'sigmethod'} eq '') {
+ if ($ltitools{$itemid}{'sigmethod'} ne 'HMAC-SHA1') {
+ $haschanges{$itemid} = 1;
+ }
+ } elsif ($values->{$itemid}{'sigmethod'} ne $ltitools{$itemid}{'sigmethod'}) {
+ $haschanges{$itemid} = 1;
+ }
+ foreach my $size ('width','height') {
+ $env{'form.ltitools_'.$size.'_'.$i} =~ s/^\s+//;
+ $env{'form.ltitools_'.$size.'_'.$i} =~ s/\s+$//;
+ if ($env{'form.ltitools_'.$size.'_'.$i} =~ /^\d+$/) {
+ $ltitools{$itemid}{'display'}{$size} = $env{'form.ltitools_'.$size.'_'.$i};
+ if (ref($values->{$itemid}{'display'}) eq 'HASH') {
+ if ($values->{$itemid}{'display'}{$size} ne $ltitools{$itemid}{'display'}{$size}) {
+ $haschanges{$itemid} = 1;
+ }
+ } else {
+ $haschanges{$itemid} = 1;
+ }
+ } elsif (ref($values->{$itemid}{'display'}) eq 'HASH') {
+ if ($values->{$itemid}{'display'}{$size} ne '') {
+ $haschanges{$itemid} = 1;
+ }
+ }
+ }
+ foreach my $item ('linktext','explanation') {
+ $env{'form.ltitools_'.$item.'_'.$i} =~ s/^\s+//;
+ $env{'form.ltitools_'.$item.'_'.$i} =~ s/\s+$//;
+ if ($env{'form.ltitools_'.$item.'_'.$i} ne '') {
+ $ltitools{$itemid}{'display'}{$item} = $env{'form.ltitools_'.$item.'_'.$i};
+ if (ref($values->{$itemid}{'display'}) eq 'HASH') {
+ if ($values->{$itemid}{'display'}{$item} ne $ltitools{$itemid}{'display'}{$item}) {
+ $haschanges{$itemid} = 1;
+ }
+ } else {
+ $haschanges{$itemid} = 1;
+ }
+ } elsif (ref($values->{$itemid}{'display'}) eq 'HASH') {
+ if ($values->{$itemid}{'display'}{$item} ne '') {
+ $haschanges{$itemid} = 1;
+ }
+ }
+ }
+ if ($env{'form.ltitools_target_'.$i} eq 'window') {
+ $ltitools{$itemid}{'display'}{'target'} = $env{'form.ltitools_target_'.$i};
+ } elsif ($env{'form.ltitools_target_'.$i} eq 'tab') {
+ $ltitools{$itemid}{'display'}{'target'} = $env{'form.ltitools_target_'.$i};
+ } else {
+ $ltitools{$itemid}{'display'}{'target'} = 'iframe';
+ }
+ if (ref($values->{$itemid}{'display'}) eq 'HASH') {
+ if ($values->{$itemid}{'display'}{'target'} ne $ltitools{$itemid}{'display'}{'target'}) {
+ $haschanges{$itemid} = 1;
+ }
+ } else {
+ $haschanges{$itemid} = 1;
+ }
+ foreach my $extra ('passback','roster') {
+ if ($env{'form.ltitools_'.$extra.'_'.$i}) {
+ $ltitools{$itemid}{$extra} = 1;
+ if ($env{'form.ltitools_'.$extra.'valid_'.$i} ne '') {
+ my $lifetime = $env{'form.ltitools_'.$extra.'valid_'.$i};
+ $lifetime =~ s/^\s+|\s+$//g;
+ if ($lifetime =~ /^\d+\.?\d*$/) {
+ $ltitools{$itemid}{$extra.'valid'} = $lifetime;
+ }
+ }
+ }
+ if ($values->{$itemid}{$extra} ne $ltitools{$itemid}{$extra}) {
+ $haschanges{$itemid} = 1;
+ }
+ if ($values->{$itemid}{$extra.'valid'} ne $ltitools{$itemid}{$extra.'valid'}) {
+ $haschanges{$itemid} = 1;
+ }
+ }
+ my @courseconfig = &Apache::loncommon::get_env_multiple('form.ltitools_courseconfig_'.$i);
+ foreach my $item ('label','title','target','linktext','explanation','append') {
+ if (grep(/^\Q$item\E$/,@courseconfig)) {
+ $ltitools{$itemid}{'crsconf'}{$item} = 1;
+ if (ref($values->{$itemid}{'crsconf'}) eq 'HASH') {
+ if ($values->{$itemid}{'crsconf'}{$item} ne $ltitools{$itemid}{'crsconf'}{$item}) {
+ $haschanges{$itemid} = 1;
+ }
+ } else {
+ $haschanges{$itemid} = 1;
+ }
+ }
+ }
+ my @fields = &Apache::loncommon::get_env_multiple('form.ltitools_fields_'.$i);
+ foreach my $field (@fields) {
+ if ($possfield{$field}) {
+ if ($field eq 'roles') {
+ foreach my $role (@courseroles) {
+ my $choice = $env{'form.ltitools_roles_'.$role.'_'.$i};
+ if (($choice ne '') && ($posslti{$choice})) {
+ $ltitools{$itemid}{'roles'}{$role} = $choice;
+ if ($role eq 'cc') {
+ $ltitools{$itemid}{'roles'}{'co'} = $choice;
+ }
+ }
+ if (ref($values->{$itemid}{'roles'}) eq 'HASH') {
+ if ($values->{$itemid}{'roles'}{$role} ne $ltitools{$itemid}{'roles'}{$role}) {
+ $haschanges{$itemid} = 1;
+ }
+ } elsif ($ltitools{$itemid}{'roles'}{$role}) {
+ $haschanges{$itemid} = 1;
+ }
+ }
+ } else {
+ $ltitools{$itemid}{'fields'}{$field} = 1;
+ if (ref($values->{$itemid}{'fields'}) eq 'HASH') {
+ if ($values->{$itemid}{'fields'}{$field} ne $ltitools{$itemid}{'fields'}{$field}) {
+ $haschanges{$itemid} = 1;
+ }
+ } else {
+ $haschanges{$itemid} = 1;
+ }
+ }
+ }
+ }
+ if (ref($ltitools{$itemid}{'fields'}) eq 'HASH') {
+ if ($ltitools{$itemid}{'fields'}{'user'}) {
+ if ($env{'form.ltitools_userincdom_'.$i}) {
+ $ltitools{$itemid}{'incdom'} = 1;
+ }
+ if ($values->{$itemid}{'incdom'} ne $ltitools{$itemid}{'incdom'}) {
+ $haschanges{$itemid} = 1;
+ }
+ }
+ }
+ $allpos[$newpos] = $itemid;
+ }
+ if ($imgdeletions{$itemid}) {
+ $haschanges{$itemid} = 1;
+ if ($context eq 'course') {
+ my $currimgurl = $values->{$itemid}{'image'};
+ if ($currimgurl =~ m{^(\Q/uploaded/$cdom/$cnum/toollogo/$itemid\E)/([^/]+)$}) {
+ my ($path,$imagefile) = ($1,$2);
+ if ($imagefile =~ /^tn\-(.+)$/) {
+ my $origimg = $1;
+ &Apache::lonnet::removeuploadedurl("$path/$origimg");
+ }
+ &Apache::lonnet::removeuploadedurl($currimgurl);
+ }
+ }
+ #FIXME need to obsolete item in RES space
+ } elsif ($env{'form.ltitools_image_'.$i.'.filename'}) {
+ my $currimgurl = $values->{$itemid}{'image'};
+ my ($imgurl,$error) = &process_ltitools_image($r,$context,$cdom,$cnum,$confname,'ltitools_image_'.$i,
+ $itemid,$configuserok,$lonhost,$author_ok,$currimgurl);
+ if ($imgurl) {
+ $ltitools{$itemid}{'image'} = $imgurl;
+ $haschanges{$itemid} = 1;
+ }
+ if ($error) {
+ &Apache::lonnet::logthis($error);
+ $errors .= ''.$error.'';
+ }
+ } elsif ($values->{$itemid}{'image'}) {
+ $ltitools{$itemid}{'image'} = $values->{$itemid}{'image'};
+ }
+ if ($customadds{$i}) {
+ my $name = $env{'form.ltitools_custom_name_'.$i};
+ $name =~ s/(`)/'/g;
+ $name =~ s/^\s+//;
+ $name =~ s/\s+$//;
+ my $value = $env{'form.ltitools_custom_value_'.$i};
+ $value =~ s/(`)/'/g;
+ $value =~ s/^\s+//;
+ $value =~ s/\s+$//;
+ if ($name ne '') {
+ $ltitools{$itemid}{'custom'}{$name} = $value;
+ $haschanges{$itemid} = 1;
+ }
+ }
+ my %customdels;
+ my @customdeletions = &Apache::loncommon::get_env_multiple('form.ltitools_customdel_'.$i);
+ if (@customdeletions) {
+ $haschanges{$itemid} = 1;
+ }
+ map { $customdels{$_} = 1; } @customdeletions;
+ if (ref($values->{$itemid}{'custom'}) eq 'HASH') {
+ foreach my $key (keys(%{$values->{$itemid}{'custom'}})) {
+ unless ($customdels{$key}) {
+ if ($env{'form.ltitools_customval_'.$key.'_'.$i} ne '') {
+ $ltitools{$itemid}{'custom'}{$key} = $env{'form.ltitools_customval_'.$key.'_'.$i};
+ }
+ if ($values->{$itemid}{'custom'}{$key} ne $env{'form.ltitools_customval_'.$key.'_'.$i}) {
+ $haschanges{$itemid} = 1;
+ }
+ }
+ }
+ }
+ unless ($switchserver) {
+ my $keyitem = 'form.ltitools_key_'.$i;
+ $env{$keyitem} =~ s/(`)/'/g;
+ if ($values->{$itemid}{'key'} ne $env{$keyitem}) {
+ $haschanges{$itemid} = 1;
+ }
+ if ($env{$keyitem} ne '') {
+ $ltitools{$itemid}{'key'} = $env{$keyitem};
+ }
+ my $secretitem = 'form.ltitools_secret_'.$i;
+ $env{$secretitem} =~ s/(`)/'/g;
+ if ($values->{$itemid}{'usable'}) {
+ if ($env{'form.ltitools_changesecret_'.$i}) {
+ if ($env{$secretitem} ne '') {
+ if ($privnum && $cipher) {
+ $ltitools{$itemid}{'secret'} = $cipher->encrypt_hex($env{$secretitem});
+ $ltitools{$itemid}{'cipher'} = $privnum;
+ } else {
+ $ltitools{$itemid}{'secret'} = $env{$secretitem};
+ }
+ $haschanges{$itemid} = 1;
+ }
+ } else {
+ $ltitools{$itemid}{'secret'} = $values->{$itemid}{'secret'};
+ $ltitools{$itemid}{'cipher'} = $values->{$itemid}{'cipher'};
+ }
+ } elsif ($env{$secretitem} ne '') {
+ if ($privnum && $cipher) {
+ $ltitools{$itemid}{'secret'} = $cipher->encrypt_hex($env{$secretitem});
+ $ltitools{$itemid}{'cipher'} = $privnum;
+ } else {
+ $ltitools{$itemid}{'secret'} = $env{$secretitem};
+ }
+ $haschanges{$itemid} = 1;
+ }
+ }
+ unless ($haschanges{$itemid}) {
+ foreach my $key (keys(%{$values->{$itemid}})) {
+ if (ref($values->{$itemid}{$key}) eq 'HASH') {
+ if (ref($ltitools{$itemid}{$key}) eq 'HASH') {
+ foreach my $innerkey (keys(%{$values->{$itemid}{$key}})) {
+ unless (exists($ltitools{$itemid}{$key}{$innerkey})) {
+ $haschanges{$itemid} = 1;
+ last;
+ }
+ }
+ } elsif (keys(%{$values->{$itemid}{$key}}) > 0) {
+ $haschanges{$itemid} = 1;
+ }
+ }
+ last if ($haschanges{$itemid});
+ }
+ }
+ }
+ }
+ }
+ if (@allpos > 0) {
+ my $idx = 0;
+ foreach my $itemid (@allpos) {
+ if ($itemid ne '') {
+ $ltitools{$itemid}{'order'} = $idx;
+ if (ref($values) eq 'HASH') {
+ if (ref($values->{$itemid}) eq 'HASH') {
+ if ($values->{$itemid}{'order'} ne $idx) {
+ $haschanges{$itemid} = 1;
+ }
+ }
+ }
+ $idx ++;
+ }
+ }
+ }
+ if (keys(%haschanges)) {
+ foreach my $entry (keys(%haschanges)) {
+ $changes->{$entry} = $ltitools{$entry};
+ }
+ if (ref($lastactref) eq 'HASH') {
+ $lastactref->{'courseltitools'} = 1;
+ }
+ }
+ return $errors;
+}
+
+sub process_ltitools_image {
+ my ($r,$context,$dom,$cnum,$confname,$caller,$itemid,$configuserok,$switch,$author_ok,$currimg) = @_;
+ my $filename = $env{'form.'.$caller.'.filename'};
+ my ($error,$url);
+ my ($width,$height) = (21,21);
+ if ($configuserok eq 'ok') {
+ if ($switch) {
+ $error = &mt('Upload of Tool Provider (LTI) icon is not permitted to this server: [_1]',
+ $switch);
+ } elsif ($author_ok eq 'ok') {
+ my ($result,$imageurl,$madethumb);
+ if ($context eq 'domain') {
+ ($result,$imageurl,$madethumb) =
+ &Apache::lonconfigsettings::publishlogo($r,'upload',$caller,$dom,$confname,
+ "ltitools/$itemid/icon",$width,$height);
+ } else {
+ ($result,$imageurl,$madethumb) = &processlogo($dom,$cnum,$caller,$currimg,$itemid,$width,$height);
+ }
+ if ($result eq 'ok') {
+ if ($madethumb) {
+ my ($path,$imagefile) = ($imageurl =~ m{^(.+)/([^/]+)$});
+ my $imagethumb = "$path/tn-".$imagefile;
+ $url = $imagethumb;
+ } else {
+ $url = $imageurl;
+ }
+ } else {
+ if ($context eq 'domain') {
+ $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$filename,$result);
+ } else {
+ $error = &mt("Upload of [_1] failed because an error occurred. Error was: [_2].",$filename,$result);
+ }
+ }
+ } else {
+ $error = &mt("Upload of [_1] failed because an author role could not be assigned to a Domain Configuration user ([_2]) in domain: [_3]. Error was: [_4].",$filename,$confname,$dom,$author_ok);
+ }
+ } else {
+ $error = &mt("Upload of [_1] failed because a Domain Configuration user ([_2]) could not be created in domain: [_3]. Error was: [_4].",$filename,$confname,$dom,$configuserok);
+ }
+ return ($url,$error);
+}
+
+sub processlogo {
+ my ($dom,$cnum,$caller,$currimg,$itemid,$width,$height) = @_;
+ my ($result,$imageurl,$madethumb);
+ if ($env{"form.$caller.filename"} ne '') {
+ unless ($caller eq 'ltitools_add_image') {
+ if ($currimg =~ m{^(\Q/uploaded/$dom/$cnum/toollogo/$itemid\E)/([^/]+)$}) {
+ my ($path,$imagefile) = ($1,$2);
+ if ($imagefile =~ /^tn\-(.+)$/) {
+ my $origimg = $1;
+ &Apache::lonnet::removeuploadedurl("$path/$origimg");
+ }
+ &Apache::lonnet::removeuploadedurl($currimg);
+ }
+ }
+ $imageurl = &Apache::lonnet::userfileupload($caller,'toollogo',"toollogo/$itemid",
+ '','','',$cnum,$dom,$width,$height);
+ if ($imageurl =~ m{^(\Q/uploaded/$dom/$cnum/toollogo/$itemid\E)/([^/]+)$}) {
+ my ($path,$imagefile) = ($1,$2);
+ $result = 'ok';
+ my $thumburl = "$path/tn-".$imagefile;
+ my ($rtncode,$info);
+ my $res = &Apache::lonnet::getuploaded('HEAD',$thumburl,$dom,$cnum,\$info,\$rtncode);
+ if ($res eq 'ok') {
+ $madethumb = 1;
+ }
+ } elsif ($imageurl eq '/adm/notfound.html') {
+ undef($imageurl);
+ $result = 'store failed';
+ } elsif ($imageurl =~ /^error: (.+)$/) {
+ $result = $1;
+ }
+ }
+ return ($result,$imageurl,$madethumb);
+}
+
sub get_sec_str {
my ($entry,$num) = @_;
my @secs = &Apache::loncommon::get_env_multiple('form.'.$entry.'_sections_'.$num);
@@ -1811,12 +2516,15 @@ sub check_clone {
sub store_changes {
my ($cdom,$cnum,$prefs_order,$actions,$prefs,$values,$changes,$crstype) = @_;
my ($chome,$output);
- my (%storehash,@delkeys,@need_env_update,@oldcloner,%oldlinkprot);
+ my (%storehash,@delkeys,@need_env_update,@oldcloner,%oldlinkprot,%oldltitools);
if ((ref($values) eq 'HASH') && (ref($changes) eq 'HASH')) {
if (ref($values->{'linkprot'}) eq 'HASH') {
%oldlinkprot = %{$values->{'linkprot'}};
}
delete($values->{'linkprot'});
+ if (ref($values->{'ltitools'}) eq 'HASH') {
+ %oldltitools = %{$values->{'ltitools'}};
+ }
%storehash = %{$values};
} else {
if ($crstype eq 'Community') {
@@ -1831,6 +2539,8 @@ sub store_changes {
$numchanges = scalar(keys(%{$changes}));
if (($numchanges == 1) && (exists($changes->{'linkprot'}))) {
$skipstore = 1;
+ } elsif (($numchanges == 1) && (exists($changes->{'ltitools'}))) {
+ $skipstore = 1;
} elsif (!$numchanges) {
if ($crstype eq 'Community') {
$output = &mt('No changes made to community settings.');
@@ -1867,6 +2577,8 @@ sub store_changes {
}
} elsif ($item eq 'linkprot') {
$output .= &store_linkprot($cdom,$cnum,'course',$changes->{$item},\%oldlinkprot);
+ } elsif ($item eq 'ltitools') {
+ $output .= &store_ltitools($cdom,$cnum,'course',$changes->{$item},\%oldltitools);
} else {
if (ref($prefs->{$item}->{'ordered'}) eq 'ARRAY') {
my @settings = @{$prefs->{$item}->{'ordered'}};
@@ -1898,14 +2610,88 @@ sub store_changes {
if ($msg ne '') {
$output .= ''.&Apache::lonhtmlcommon::confirm_success(&mt($displayname)).'';
}
+ } elsif ($key eq 'timezone') {
+ next unless ((exists($changes->{$item}{$key})) || (exists($changes->{$item}{'tzover'})));
+ my ($displayname,$text);
+ $text = $prefs->{$item}->{'itemtext'}{$key};
+ my $displayval;
+ if (exists($changes->{$item}{$key})) {
+ $displayname = &mt($text);
+ $storehash{$key} = $changes->{$item}{$key};
+ if ($changes->{$item}{$key} ne '') {
+ $displayval = ''.$changes->{$item}{$key}.'';
+ } else {
+ push(@delkeys,$key);
+ if (exists($values->{'tzover'})) {
+ push(@delkeys,'tzover');
+ }
+ $output .= ''.&Apache::lonhtmlcommon::confirm_success(&mt('Deleted setting for [_1]',
+ ''.$displayname.'')).'';
+ }
+ }
+ unless (grep(/^\Q$key\E$/,@delkeys)) {
+ if (exists($changes->{$item}{'tzover'})) {
+ $storehash{'tzover'} = $changes->{$item}{'tzover'};
+ my $tzovertext;
+ if ($changes->{$item}{'tzover'} ne '') {
+ $tzovertext = &mt('Course Time Zone overrides individual user preference');
+ } else {
+ push(@delkeys,'tzover');
+ $tzovertext = &mt('Course Time Zone does not override individual user preference');
+ }
+ if ($displayval eq '') {
+ $output .= ''.&Apache::lonhtmlcommon::confirm_success($tzovertext).'';
+ } else {
+ $displayval .= '
'.(' 'x5).$tzovertext;
+ }
+ }
+ if ($displayval ne '') {
+ $output .= ''.&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]',
+ ''.$displayname.'',$displayval)).'';
+ }
+ }
} else {
next if (!exists($changes->{$item}{$key}));
my ($displayname,$text);
$text = $prefs->{$item}->{'itemtext'}{$key};
my $displayval;
- unless (($key eq 'co-owners') || ($key eq 'discussion_post_fonts')) {
+ unless (($key eq 'co-owners') || ($key eq 'discussion_post_fonts') || ($key eq 'extresource')) {
$displayval = $changes->{$item}{$key};
}
+ if (($item eq 'grading') && ($key eq 'grading')) {
+ if ($displayval eq 'standard') {
+ my $hidetotals;
+ if (exists($changes->{$item}{'hidetotals'})) {
+ if ($changes->{$item}{'hidetotals'} eq '') {
+ if (exists($values->{'hidetotals'})) {
+ push(@delkeys,'hidetotals');
+ }
+ } else {
+ $hidetotals = $changes->{$item}{'hidetotals'};
+ }
+ } elsif (exists($values->{'hidetotals'})) {
+ $hidetotals = $values->{'hidetotals'};
+ }
+ if ($hidetotals eq '') {
+ $displayval = &mt('standard with "hide course totals" set to "No"');
+ if (exists($values->{'hidetotals'})) {
+ push(@delkeys,'hidetotals');
+ }
+ } elsif ($hidetotals =~ /^([\w,]+)$/) {
+ my $secstr = $1;
+ my @secs = split(/,/,$secstr);
+ if (grep(/^all$/,@secs)) {
+ $displayval = &mt('standard with "hide course totals" set to "Yes" for all users');
+ $hidetotals = 'all';
+ } else {
+ $displayval = &mt('standard with "hide course totals" set to "Yes" for users in section(s): [_1]',join(', ',@secs));
+ }
+ $storehash{'hidetotals'} = $hidetotals;
+ }
+ } elsif (exists($values->{'hidetotals'})) {
+ push(@delkeys,'hidetotals');
+ }
+ }
if ($item eq 'feedback') {
if ($key =~ /^(question|policy|comment)(\.email)\.text$/) {
$text = $prefs->{$item}->{'itemtext'}{$1.$2};
@@ -2028,6 +2814,37 @@ sub store_changes {
} elsif ($changes->{$item}{$key} eq '0') {
$displayval = &mt('No');
}
+ } elsif ($key eq 'extresource') {
+ if ($changes->{$item}{$key} eq 'iframe') {
+ $displayval = &mt('In iframe');
+ } else {
+ my ($selected,$reuse,$width,$height) = split(/:/,$changes->{$item}{$key});
+ if ($selected eq 'tab') {
+ if ($reuse) {
+ $displayval = &mt('[_1]In tab[_2],[_3] and tab re-used for different external resources in course',
+ "'","'",'
');
+ } else {
+ $displayval = &mt('[_1]In tab[_2],[_3] with new tab for each external resource in course',
+ "'","'",'
');
+ }
+ } elsif ($selected eq 'window') {
+ if ($reuse) {
+ $displayval = &mt('[_1]In pop-up window[_2],[_3] and window re-used for different external resources in course',
+ "'","'",'
');
+ } else {
+ $displayval = &mt('[_1]In pop-up window[_2],[_3] with new window for each external resource in course',
+ "'","'",'
');
+ }
+ if (($width ne '') || ($height ne '')) {
+ if ($width ne '') {
+ $displayval .= '
'.&mt('Window width: [_1]px',$width);
+ }
+ if ($height ne '') {
+ $displayval .= '
'.&mt('Window height: [_1]px',$height);
+ }
+ }
+ }
+ }
}
if ($key eq 'co-owners') {
if (ref($changes->{$item}{$key}) eq 'HASH') {
@@ -2099,9 +2916,11 @@ sub store_changes {
$output .= ''.&Apache::lonhtmlcommon::confirm_success(&mt('Numbered menu collections:')).'
'.
$displayval.'';
} else {
+ unless (($key eq 'extresource') && ($changes->{$item}{$key} ne 'iframe')) {
+ $displayval = "'$displayval'";
+ }
$output .= ''.&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]',
- ''.$displayname.'',
- "'$displayval'"));
+ ''.$displayname.'',$displayval));
if ($key eq 'url') {
my $bkuptime=time;
$output .= (' 'x2).&mt('(Previous URL backed up)').': '.
@@ -2282,7 +3101,7 @@ sub store_linkprot {
my %values = %{$changes->{$id}};
my %desc = &linkprot_names();
my $display;
- foreach my $title ('name','lifetime','version','key','secret','returnurl') {
+ foreach my $title ('name','lifetime','version','key','secret','returnurl','passbackformat') {
if (($title eq 'key') || ($title eq 'secret')) {
if (ref($ltienc{$id}) eq 'HASH') {
if (exists($ltienc{$id}{$title})) {
@@ -2300,7 +3119,13 @@ sub store_linkprot {
}
} elsif ($title eq 'returnurl') {
if ($values{$title}) {
- $display .= &mt('Return URL parameter').': '.$values{$title}.', ';
+ $display .= &mt('Return URL parameter').': '.$values{$title}.', ';
+ }
+ } elsif ($title eq 'passbackformat') {
+ if ($values{$title} eq '1.0') {
+ $display .= &mt('Can return grades to Launcher with Outcomes Service 1.0 format').', ';
+ } elsif ($values{$title} eq '1.1') {
+ $display .= &mt('Can return grades to Launcher with Outcomes Service 1.1 format').', ';
}
} else {
$display .= $desc{$title}.': '.$values{$title}.', ';
@@ -2358,6 +3183,214 @@ sub store_linkprot {
return $output;
}
+sub store_ltitools {
+ my ($cdom,$cnum,$context,$changes,$oldltitools) = @_;
+ my ($home,$ltitools_save_error,$output,$error,%toolsenc,@deletions);
+ my %lt = <itools_names();
+ my @courseroles = ('cc','in','ta','ep','st');
+ my @allfields = ('fullname','firstname','lastname','email','user','roles');
+ if ($context eq 'domain') {
+ $home = &Apache::lonnet::domain($cdom,'primary');
+ } else {
+ $home = &Apache::lonnet::homeserver($cnum,$cdom);
+ }
+ if (ref($changes) eq 'HASH') {
+ foreach my $id (sort { $a <=> $b } keys(%{$changes})) {
+ if (ref($changes->{$id}) eq 'HASH') {
+ if (exists($changes->{$id}->{'key'})) {
+ $toolsenc{$id}{'key'} = $changes->{$id}->{'key'};
+ delete($changes->{$id}->{'key'});
+ }
+ if (exists($changes->{$id}->{'secret'})) {
+ $toolsenc{$id}{'secret'} = $changes->{$id}->{'secret'};
+ delete($changes->{$id}->{'secret'});
+ } elsif (ref($oldltitools->{$id}) eq 'HASH') {
+ if (exists($oldltitools->{$id}{'usable'})) {
+ $changes->{$id}->{'usable'} = 1;
+ }
+ if (exists($oldltitools->{$id}{'cipher'})) {
+ $changes->{$id}->{'cipher'} = $oldltitools->{$id}{'cipher'};
+ }
+ }
+ }
+ }
+ }
+ my @ids=&Apache::lonnet::current_machine_ids();
+ if (keys(%toolsenc) > 0) {
+ unless (($home eq 'no_host') || ($home eq '')) {
+ my $allowed;
+ foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } }
+ if ($allowed) {
+ if (($context eq 'domain') ||
+ (($context eq 'course') &&
+ (&Apache::lonnet::put('nohist_toolsenc',\%toolsenc,$cdom,$cnum,1) eq 'ok'))) {
+ foreach my $id (keys(%toolsenc)) {
+ if (exists($toolsenc{$id}{'secret'})) {
+ $changes->{$id}->{'usable'} = 1;
+ }
+ }
+ } else {
+ $ltitools_save_error = 1;
+ }
+ }
+ }
+ }
+ unless ($ltitools_save_error) {
+ if ($context eq 'course') {
+ if (&Apache::lonnet::put('ltitools',$changes,$cdom,$cnum,1) eq 'ok') {
+ my $hashid=$cdom.'_'.$cnum;
+ &Apache::lonnet::devalidate_cache_new('courseltitools',$hashid);
+ unless (($home eq 'no_host') || ($home eq '')) {
+ if (grep(/^\Q$home\E$/,@ids)) {
+ &Apache::lonnet::devalidate_cache_new('crsltitoolsenc',$hashid);
+ }
+ }
+ } else {
+ $ltitools_save_error = 1;
+ }
+ }
+ unless ($ltitools_save_error) {
+ my %bynum;
+ foreach my $itemid (sort(keys(%{$changes}))) {
+ my $position = $changes->{$itemid}{'order'};
+ $bynum{$position} = $itemid;
+ }
+ foreach my $pos (sort { $a <=> $b } keys(%bynum)) {
+ my $itemid = $bynum{$pos};
+ if (ref($changes->{$itemid}) ne 'HASH') {
+ $output .= ''.&mt('Deleted: [_1]',$changes->{$itemid}).'';
+ } else {
+ $output .= ''.$changes->{$itemid}{'title'}.'';
+ if ($changes->{$itemid}{'image'}) {
+ $output .= ' '.
+ '';
+ }
+ $output .= '';
+ my $position = $pos + 1;
+ $output .= '- '.&mt('Order: [_1]',$position).'
';
+ foreach my $item ('version','msgtype','sigmethod','url','lifetime') {
+ if ($changes->{$itemid}{$item} ne '') {
+ $output .= '- '.$lt{$item}.': '.$changes->{$itemid}{$item}.'
';
+ }
+ }
+ if (ref($toolsenc{$itemid}) eq 'HASH') {
+ foreach my $item ('key','secret') {
+ if (exists($toolsenc{$itemid}{$item})) {
+ if ($item eq 'secret') {
+ $output .= '- '.$lt{$item}.': ['.&mt('not shown').']
';
+ } else {
+ $output .= '- '.$lt{$item}.': '.$toolsenc{$itemid}{$item}.'
';
+ }
+ }
+ }
+ }
+ $output .= '- '.&mt('Configurable in course:');
+ my @possconfig = ('label','title','target','linktext','explanation','append');
+ my $numconfig = 0;
+ if (ref($changes->{$itemid}{'crsconf'}) eq 'HASH') {
+ foreach my $item (@possconfig) {
+ if ($changes->{$itemid}{'crsconf'}{$item}) {
+ $numconfig ++;
+ $output .= ' "'.$lt{'crs'.$item}.'"';
+ }
+ }
+ }
+ if (!$numconfig) {
+ $output .= ' '.&mt('None');
+ }
+ $output .= '
';
+ foreach my $item ('passback','roster') {
+ $output .= '- '.$lt{$item}.' ';
+ if ($changes->{$itemid}{$item}) {
+ $output .= &mt('Yes');
+ if ($changes->{$itemid}{$item.'valid'}) {
+ if ($item eq 'passback') {
+ $output .= ' '.&mt('valid for at least [quant,_1,day] after launch',
+ $changes->{$itemid}{$item.'valid'});
+ } else {
+ $output .= ' '.&mt('valid for at least [quant,_1,second] after launch',
+ $changes->{$itemid}{$item.'valid'});
+ }
+ }
+ } else {
+ $output .= &mt('No');
+ }
+ $output .= '
';
+ }
+ if (ref($changes->{$itemid}{'display'}) eq 'HASH') {
+ my $displaylist;
+ if ($changes->{$itemid}{'display'}{'target'}) {
+ $displaylist = &mt('Display target').': '.
+ $changes->{$itemid}{'display'}{'target'}.',';
+ }
+ foreach my $size ('width','height') {
+ if ($changes->{$itemid}{'display'}{$size}) {
+ $displaylist .= (' 'x2).$lt{$size}.': '.
+ $changes->{$itemid}{'display'}{$size}.',';
+ }
+ }
+ if ($displaylist) {
+ $displaylist =~ s/,$//;
+ $output .= '- '.$displaylist.'
';
+ }
+ foreach my $item ('linktext','explanation') {
+ if ($changes->{$itemid}{'display'}{$item}) {
+ $output .= '- '.$lt{$item}.': '.$changes->{$itemid}{'display'}{$item}.'
';
+ }
+ }
+ }
+ if (ref($changes->{$itemid}{'fields'}) eq 'HASH') {
+ my $fieldlist;
+ foreach my $field (@allfields) {
+ if ($changes->{$itemid}{'fields'}{$field}) {
+ $fieldlist .= (' 'x2).$lt{$field}.',';
+ }
+ }
+ if ($fieldlist) {
+ $fieldlist =~ s/,$//;
+ if ($changes->{$itemid}{'fields'}{'user'}) {
+ if ($changes->{$itemid}{'incdom'}) {
+ $fieldlist .= ' ('.&mt('username:domain').')';
+ } else {
+ $fieldlist .= ' ('.&mt('username').')';
+ }
+ }
+ $output .= '- '.&mt('Data sent').':'.$fieldlist.'
';
+ }
+ }
+ if (ref($changes->{$itemid}{'roles'}) eq 'HASH') {
+ my $rolemaps;
+ foreach my $role (@courseroles) {
+ if ($changes->{$itemid}{'roles'}{$role}) {
+ $rolemaps .= (' 'x2).&Apache::lonnet::plaintext($role,'Course').'='.
+ $changes->{$itemid}{'roles'}{$role}.',';
+ }
+ }
+ if ($rolemaps) {
+ $rolemaps =~ s/,$//;
+ $output .= '- '.&mt('Role mapping:').$rolemaps.'
';
+ }
+ }
+ if (ref($changes->{$itemid}{'custom'}) eq 'HASH') {
+ my $customlist;
+ if (keys(%{$changes->{$itemid}{'custom'}})) {
+ foreach my $key (sort(keys(%{$changes->{$itemid}{'custom'}}))) {
+ $customlist .= $key.':'.$changes->{$itemid}{'custom'}{$key}.(' 'x2);
+ }
+ }
+ if ($customlist) {
+ $output .= '- '.&mt('Custom items').': '.$customlist.'
';
+ }
+ }
+ $output .= '
';
+ }
+ }
+ }
+ }
+ return $output;
+}
+
sub update_env {
my ($cnum,$cdom,$chome,$need_env_update,$storehash) = @_;
my $count = 0;
@@ -2490,10 +3523,15 @@ sub get_course {
sub get_jscript {
my ($cid,$cdom,$phase,$crstype,$settings,$noedit) = @_;
my ($can_toggle_cat,$can_categorize) = &can_modify_catsettings($cdom,$crstype);
- my ($jscript,$categorize_js,$loncaparev_js,$instcode_js);
+ my ($jscript,$categorize_js,$loncaparev_js,$instcode_js,$extresource_js,$localization_js);
my $stubrowse_js = &Apache::loncommon::studentbrowser_javascript();
my $browse_js = &Apache::loncommon::browser_and_searcher_javascript('parmset');
my $cloners_js = &cloners_javascript($phase);
+ my $currltitools;
+ if (ref($settings) eq 'HASH') {
+ $currltitools = $settings->{'ltitools'};
+ }
+ my $ltitools_js = &Apache::lonconfigsettings::ltitools_javascript($currltitools);
my @code_order;
if ($crstype ne 'Community') {
if (ref($settings) eq 'HASH') {
@@ -2513,7 +3551,7 @@ sub get_jscript {
$local_to_standard{$code_order[$i]} = $standardnames[$i];
}
foreach my $cloner (@cloners) {
- if (($cloner !~ /^\Q*:\E$match_domain$/) &&
+ if (($cloner !~ /^\Q*:\E$match_domain$/) &&
($cloner !~ /^$match_username\:$match_domain$/)) {
foreach my $item (split(/\&/,$cloner)) {
my ($key,$val) = split(/\=/,$item);
@@ -2614,7 +3652,7 @@ function syllabusinfo() {
}
}
ENDSCRIPT
- my $menuitems_js;
+ my ($menuitems_js,$grading_js);
unless ($noedit) {
my $collections;
my $next = 1;
@@ -2696,14 +3734,98 @@ function toggleAddmenucoll() {
}
}
ENDSCRIPT
+ $grading_js = <<"ENDSCRIPT";
+function toggleGrading(form) {
+ if (document.getElementById('hidetotalsdiv')) {
+ var totalsdivid = document.getElementById('hidetotalsdiv');
+ var selname = form.elements['grading'];
+ if (selname) {
+ var current = selname.options[selname.selectedIndex].value
+ if (current == 'standard') {
+ totalsdivid.style.display = 'inline-block';
+ } else {
+ totalsdivid.style.display = 'none';
+ }
+ }
+ }
+ return;
+}
+
+function toggleHiddenTotalsSec(form) {
+ if (document.getElementById('sectotalsdiv')) {
+ var sectotalsdivid = document.getElementById('sectotalsdiv');
+ var radioname = form.elements['hidetotals'];
+ if (radioname) {
+ if (radioname.length > 0) {
+ var setvis;
+ for (var i=0; i'."\n".
- '// '."\n".
- ''."\n".$stubrowse_js."\n";
+ $cloners_js."\n".$instcode_js."\n".$localization_js."\n".
+ $syllabus_js."\n".$menuitems_js."\n".$extresource_js."\n".
+ $grading_js."\n".&linkprot_javascript()."\n".'//]]>'."\n".
+ ''."\n".$stubrowse_js."\n".$ltitools_js."\n";
return $jscript;
}
@@ -2790,38 +3912,6 @@ ENDSCRIPT
sub linkprot_javascript {
return <<"ENDSCRIPT";
-function toggleLinkProt(form,num,item) {
- var radioname = '';
- var currdivid = '';
- var newdivid = '';
- if ((document.getElementById('linkprot_divcurr'+item+'_'+num)) &&
- (document.getElementById('linkprot_divchg'+item+'_'+num))) {
- currdivid = document.getElementById('linkprot_divcurr'+item+'_'+num);
- newdivid = document.getElementById('linkprot_divchg'+item+'_'+num);
- radioname = form.elements['linkprot_change'+item+'_'+num];
- if (radioname) {
- if (radioname.length > 0) {
- var setvis;
- for (var i=0; i';
$editsyllabus = &mt('[_1]Edit[_2]','',
- '');
+ '');
}
my %items = (
'url' => {
@@ -3035,7 +4115,7 @@ sub print_courseinfo {
next if (!$env{'course.'.$env{'request.course.id'}.'.internal.uniquecode'});
}
unless (($item eq 'cloners') || ($item eq 'rolenames')) {
- $colspan = 2;
+ $colspan = 2;
}
$count ++;
if (exists $items{$item}{advanced} && $items{$item}{advanced} == 1) {
@@ -3218,12 +4298,12 @@ sub print_courseinfo {
if ($clonesrc =~ m{/$match_domain/$match_courseid}) {
my %clonesrcinfo = &Apache::lonnet::coursedescription($clonesrc);
if ($clonesrcinfo{'description'}) {
- $clonedfrom = $clonesrcinfo{'description'}.' '.($clonesrc);
+ $clonedfrom = $clonesrcinfo{'description'}.' '.($clonesrc);
}
}
$datatable .= $clonedfrom;
} elsif ($item eq 'uniquecode') {
- my $code = $env{'course.'.$env{'request.course.id'}.'.internal.uniquecode'};
+ my $code = $env{'course.'.$env{'request.course.id'}.'.internal.uniquecode'};
if ($code) {
$datatable .= $code;
}
@@ -3270,12 +4350,12 @@ sub print_courseinfo {
} elsif ($uploaded) {
$datatable .= &mt('Uploaded file');
} else {
- $datatable .= &mt('Standard template');
+ $datatable .= &mt('Standard template');
}
$datatable .= (' ' x 2).
&mt('[_1]View[_2]',
'',
- '');
+ '');
} elsif ($item eq 'loncaparev') {
my $loncaparev = $env{'course.'.$env{'request.course.id'}.'.internal.releaserequired'};
my $showreqd;
@@ -3300,7 +4380,7 @@ sub new_cloners_dom_row {
my ($output,$checkedon,$checkedoff);
if ($newdom ne '') {
if ($num eq $default) {
- $checkedon = 'checked="checked" ';
+ $checkedon = 'checked="checked" ';
} else {
$checkedoff = 'checked="checked" ';
}
@@ -3451,7 +4531,7 @@ ENDSCRIPT
sub display_loncaparev_constraints {
my ($r,$navmap,$loncaparev,$crstype) = @_;
- my ($reqdmajor,$reqdminor);
+ my ($reqdmajor,$reqdminor);
my $cid = $env{'request.course.id'};
my $cdom = $env{'course.'.$cid.'.domain'};
my $cnum = $env{'course.'.$cid.'.num'};
@@ -3721,7 +4801,7 @@ sub display_loncaparev_constraints {
if (ref($fromblocks{$type}) eq 'HASH') {
foreach my $rev (keys(%{$fromblocks{$type}})) {
my ($major,$minor) = split(/\./,$rev);
- ($reqdmajor,$reqdminor) =
+ ($reqdmajor,$reqdminor) =
&Apache::lonrelrequtils::update_reqd_loncaparev($major,$minor,$reqdmajor,$reqdminor);
$output .= &Apache::loncommon::start_data_table_row().
''.$rev.' | '.$lt{$type}.' | ';
@@ -3808,7 +4888,7 @@ sub display_loncaparev_constraints {
&Apache::lonrelrequtils::update_reqd_loncaparev($major,$minor,
$reqdmajor,$reqdminor);
$checkedrev{$key} = 1;
- }
+ }
push(@{$byresponsetype{$symb}{$rev}},$key);
$allmaps{$enclosing_map} = 1;
}
@@ -3845,10 +4925,7 @@ sub display_loncaparev_constraints {
}
}
}
- my $suppmap = 'supplemental.sequence';
- my ($suppcount,$supptools,$errors) = (0,0,0);
- ($suppcount,$supptools,$errors) = &Apache::loncommon::recurse_supplemental($cnum,$cdom,
- $suppmap,$suppcount,$supptools,$errors);
+ my $supptools = &Apache::lonnet::count_supptools($cnum,$cdom,1,1);
my $mapres_header = ''.
&mt('Requirements for specific folders or resources').
'';
@@ -4063,7 +5140,7 @@ sub show_contents_view {
sub releases_by_map {
my ($r,$bymap,$url,$scopeorder,$lt) = @_;
return unless ((ref($bymap) eq 'HASH') && (ref($scopeorder) eq 'ARRAY'));
- my $newrow = 0;
+ my $newrow = 0;
if (ref($bymap->{$url}) eq 'HASH') {
foreach my $rev (sort(keys(%{$bymap->{$url}}))) {
if ($newrow) {
@@ -4355,9 +5432,23 @@ sub print_localization {
if ($item eq 'timezone') {
my $includeempty = 1;
my $timezone = &Apache::lonlocal::gettimezone();
+ my $onchange;
+ unless ($noedit) {
+ $onchange = ' onchange="javascript:toggleTimeZone();"';
+ }
+ my $id = ' id="LC_set_timezone"';
$datatable .=
- &Apache::loncommon::select_timezone($item,$timezone,undef,
- $includeempty,$disabled);
+ &Apache::loncommon::select_timezone($item,$timezone,$onchange,
+ $includeempty,$id,$disabled);
+ my $tzsty = 'none';
+ if ($timezone ne '') {
+ $tzsty = 'block';
+ }
+ $datatable .= ''.
+ ''.
+ &mt('Override individual user preference?').
+ &yesno_radio('tzover',$settings,undef,1,'',$noedit).
+ ' ';
} elsif ($item eq 'datelocale') {
my $includeempty = 1;
my $locale_obj = &Apache::lonlocal::getdatelocale();
@@ -4370,7 +5461,7 @@ sub print_localization {
undef,$includeempty,$disabled);
} else {
if ($settings->{$item} eq '') {
- unless ($noedit) {
+ unless ($noedit) {
$datatable .= ' | '.
&Apache::loncommon::select_language('languages_0','',1);
}
@@ -4407,8 +5498,8 @@ sub print_localization {
&Apache::loncommon::select_language('languages_'.$num,'',1).
''.
' | '.&Apache::loncommon::end_data_table_row();
- }
- $datatable .= &Apache::loncommon::end_data_table().'
';
+ }
+ $datatable .= &Apache::loncommon::end_data_table().'
';
}
}
$datatable .= &item_table_row_end();
@@ -4582,7 +5673,7 @@ sub select_recipient {
}
sub select_sections {
- my ($item,$num,$sections,$selected,$noedit) = @_;
+ my ($item,$num,$sections,$selected,$noedit,$allval) = @_;
my ($output,@currsecs,$allsec,$disabled);
if (ref($selected) eq 'ARRAY') {
@currsecs = @{$selected};
@@ -4598,16 +5689,24 @@ sub select_sections {
my $mult;
if (@{$sections} > 1) {
$mult = ' multiple="multiple"';
+ my $size;
if (@{$sections} > 3) {
- $mult .= ' size="4"';
+ $size = 4;
+ } else {
+ $size = 1 + scalar(@{$sections});
}
+ $mult .= ' size="'.$size.'"';
+ }
+ my $name = $item.'_sections';
+ unless ($item eq 'hidetotals') {
+ $name .= '_'.$num;
}
- $output = '