--- loncom/interface/courseprefs.pm 2023/07/20 12:47:10 1.125 +++ loncom/interface/courseprefs.pm 2025/03/15 01:03:33 1.134 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Handler to set configuration settings for a course # -# $Id: courseprefs.pm,v 1.125 2023/07/20 12:47:10 raeburn Exp $ +# $Id: courseprefs.pm,v 1.134 2025/03/15 01:03:33 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -372,6 +372,12 @@ sub handler { my %values=&Apache::lonnet::dump('environment',$cdom,$cnum); my %linkprot=&Apache::lonnet::dump('lti',$cdom,$cnum,undef,undef,undef,1); + my %domdefs = &Apache::lonnet::get_domain_defaults($cdom); + unless ($phase eq 'process') { + if (ref($domdefs{'linkprotsuggested'}) eq 'HASH') { + $values{'suggested'} = $domdefs{'linkprotsuggested'}; + } + } 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); @@ -694,6 +700,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,9 +799,38 @@ sub print_config_box { '; + if ($action eq 'linkprot') { + if ((ref($settings) eq 'HASH') && (ref($settings->{'suggested'}) eq 'HASH')) { + my $hints; + my $hintcount = 0; + foreach my $key (sort { $a <=> $b } keys(%{$settings->{'suggested'}})) { + if ((ref($settings->{'suggested'}->{$key}) eq 'HASH')) { + if (($settings->{'suggested'}->{$key}-{'name'} ne '') && + ($settings->{'suggested'}->{$key}-{'info'} ne '')) { + my $css_class = $hintcount%2?' class="LC_odd_row"':' class="LC_even_row"'; + $hints .= ''. + ''; + $hintcount ++; + } + } + } + if ($hintcount) { + $output .= ''. + ''. + ''."\n". + ''. + ''. + ''."\n". + $hints; + } + } + } if (exists $item->{'header'}->[0]->{'col1'} || exists $item->{'header'}->[0]->{'col2'}) { - $output .= ' + $output .= ' '; if (($action eq 'courseinfo') || ($action eq 'localization') || @@ -820,7 +857,7 @@ 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') { @@ -1548,6 +1585,33 @@ sub process_changes { } 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}; } @@ -1962,10 +2026,14 @@ sub process_ltitools { } else { $ltitools{$newid}{'display'}{'target'} = 'iframe'; } - foreach my $item ('passback','roster') { + foreach my $item ('passback','roster','returnurl') { if ($env{'form.ltitools_'.$item.'_add'}) { $ltitools{$newid}{$item} = 1; - if ($env{'form.ltitools_'.$item.'valid_add'} ne '') { + if ($item eq 'returnurl') { + if ($env{'form.ltitools_crs'.$item.'_add'}) { + $ltitools{$newid}{'crsconf'}{$item} = 1; + } + } elsif ($env{'form.ltitools_'.$item.'valid_add'} ne '') { my $lifetime = $env{'form.ltitools_'.$item.'valid_add'}; $lifetime =~ s/^\s+|\s+$//g; if ($lifetime =~ /^\d+\.?\d*$/) { @@ -2149,10 +2217,21 @@ sub process_ltitools { } else { $haschanges{$itemid} = 1; } - foreach my $extra ('passback','roster') { + foreach my $extra ('passback','roster','returnurl') { if ($env{'form.ltitools_'.$extra.'_'.$i}) { $ltitools{$itemid}{$extra} = 1; - if ($env{'form.ltitools_'.$extra.'valid_'.$i} ne '') { + if ($extra eq 'returnurl') { + if ($env{'form.ltitools_crs'.$extra.'_'.$i}) { + $ltitools{$itemid}{'crsconf'}{$extra} = 1; + if (ref($values->{$itemid}{'crsconf'}) eq 'HASH') { + if (!$values->{$itemid}{'crsconf'}{$extra}) { + $haschanges{$itemid} = 1; + } + } else { + $haschanges{$itemid} = 1; + } + } + } elsif ($env{'form.ltitools_'.$extra.'valid_'.$i} ne '') { my $lifetime = $env{'form.ltitools_'.$extra.'valid_'.$i}; $lifetime =~ s/^\s+|\s+$//g; if ($lifetime =~ /^\d+\.?\d*$/) { @@ -2629,6 +2708,40 @@ sub store_changes { 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}; @@ -2637,14 +2750,14 @@ sub store_changes { $displayname = &mt('Recipients of '.$text.' questions'); } } elsif ($item eq 'discussion') { - if ($key =~ /^p(lc|ch)\.roles\.denied/) { + if ($key =~ /^p(lc|ch|ac)\.roles\.denied/) { $displayname = &mt("$text (role-based)"); if ($displayval ne '') { my @roles = split(',',$displayval); @roles = map { &Apache::lonnet::plaintext($_); } @roles; $displayval = join(', ',@roles); } - } elsif ($key =~ /^p(lc|ch)\.users\.denied/) { + } elsif ($key =~ /^p(lc|ch|ac)\.users\.denied/) { $displayname = &mt("$text (specific user(s))"); } else { if ($key eq 'allow_discussion_post_editing') { @@ -3222,7 +3335,13 @@ sub store_ltitools { } } } - $output .= '
  • '.&mt('Configurable in course:'); + $output .= '
  • '; + if ($context eq 'domain') { + $output .= &mt('Configurable in course'); + } else { + $output .= &mt('Configurable for each instance of tool in course'); + } + $output .= ':'; my @possconfig = ('label','title','target','linktext','explanation','append'); my $numconfig = 0; if (ref($changes->{$itemid}{'crsconf'}) eq 'HASH') { @@ -3237,11 +3356,21 @@ sub store_ltitools { $output .= ' '.&mt('None'); } $output .= '
  • '; - foreach my $item ('passback','roster') { + foreach my $item ('passback','roster','returnurl') { $output .= '
  • '.$lt{$item}.' '; if ($changes->{$itemid}{$item}) { $output .= &mt('Yes'); - if ($changes->{$itemid}{$item.'valid'}) { + if ($item eq 'returnurl') { + if (ref($changes->{$itemid}{'crsconf'}) eq 'HASH') { + $output .= ' ['.&mt('Configurable in course').': '; + if ($changes->{$itemid}{'crsconf'}{$item}) { + $output .= &mt('Yes'); + } else { + $output .= &mt('No'); + } + $output .= ']'; + } + } elsif ($changes->{$itemid}{$item.'valid'}) { if ($item eq 'passback') { $output .= ' '.&mt('valid for at least [quant,_1,day] after launch', $changes->{$itemid}{$item.'valid'}); @@ -3589,7 +3718,7 @@ function syllabusinfo() { } } ENDSCRIPT - my $menuitems_js; + my ($menuitems_js,$grading_js); unless ($noedit) { my $collections; my $next = 1; @@ -3671,6 +3800,48 @@ 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". + $grading_js."\n".&linkprot_javascript()."\n".'//]]>'."\n". ''."\n".$stubrowse_js."\n".$ltitools_js."\n"; return $jscript; } @@ -5152,8 +5323,7 @@ sub update_releasereq { } $modified_courses = []; } - undef($registered_cleanup); - return; + return OK; } sub show_autocoowners { @@ -5568,7 +5738,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}; @@ -5584,16 +5754,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 = ''. + ' '; foreach my $sec (@{$sections}) { my $is_sel; if ((@currsecs) && (grep(/^\Q$sec\E$/,@currsecs))) { - $is_sel = 'selected="selected"'; + $is_sel = ' selected="selected"'; } $output .= ''; } @@ -6077,7 +6255,7 @@ sub print_appearance { } sub print_grading { - my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype,$noedit) = @_; + my ($cdom,$cnum,$settings,$ordered,$itemtext,$rowtotal,$crstype,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } @@ -6097,7 +6275,7 @@ sub print_grading { }, 'rndseed' => { text => ''.&mt($itemtext->{'rndseed'}).''. - ''.'
    '. + '
    '. &mt('Modifying this will make problems have different numbers and answers!'). '', input => 'selectbox', @@ -6129,7 +6307,7 @@ sub print_grading { input => 'radio', }, ); - return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype,'grading',$noedit); + return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype,'grading',$noedit,$cnum); } sub print_printouts { @@ -6474,22 +6652,35 @@ sub print_ltitools { '
    '.$lt{'linktext'}.'
    '. '
    '. '
    '.$lt{'explanation'}.'
    '. - '

    '; my %units = ( 'passback' => 'days', 'roster' => 'seconds', ); - foreach my $extra ('passback','roster') { + my %courseconfig; + if (ref($settings->{$item}) eq 'HASH') { + if (ref($settings->{$item}->{'crsconf'}) eq 'HASH') { + %courseconfig = %{$settings->{$item}->{'crsconf'}}; + } + } + foreach my $extra ('passback','roster','returnurl') { my $validsty = 'none'; my $currvalid; my $checkedon = ''; my $checkedoff = ' checked="checked"'; + my $crscheckedon = ''; + my $crscheckedoff = ' checked="checked"'; if ($settings->{$item}->{$extra}) { $checkedon = $checkedoff; $checkedoff = ''; $validsty = 'inline-block'; - if ($settings->{$item}->{$extra.'valid'} =~ /^\d+\.?\d*$/) { + if ($extra eq 'returnurl') { + if ($courseconfig{$extra}) { + $crscheckedon = ' checked="checked"'; + $crscheckedoff = ''; + } + } elsif ($settings->{$item}->{$extra.'valid'} =~ /^\d+\.?\d*$/) { $currvalid = $settings->{$item}->{$extra.'valid'}; } } @@ -6498,12 +6689,21 @@ sub print_ltitools { ''.(' 'x2). '
    '. - '
    '. - ''. - &mt("until at least [_1] $units{$extra} after launch", - ''). - '
    '; + &mt('Yes').''; + if ($extra eq 'returnurl') { + $datatable .= '
    '. + ' -- '.&mt('configurable in course').': '. + ''.(' 'x2). + ''; + } else { + $datatable .= '
    '. + ''. + &mt("until at least [_1] $units{$extra} after launch", + ''); + } + $datatable .= '
    '; } $datatable .= ''.$lt{'icon'}.': '; if ($imgsrc) { @@ -6589,14 +6789,14 @@ sub print_ltitools { } $datatable .= ''; } - $datatable .= '
  • '. + $settings->{'suggested'}->{$key}->{'name'}.'
    '.
    +                                      $settings->{'suggested'}->{$key}->{'info'}.
    +                                      '
    '.&mt('Recommendation(s) for specific launcher application(s)').'
    '.&mt('Launcher Application').''.&mt('Recommendation(s)').'
    '.&mt($item->{'header'}->[0]->{'col1'}).'
    '; - my %courseconfig; - if (ref($settings->{$item}) eq 'HASH') { - if (ref($settings->{$item}->{'crsconf'}) eq 'HASH') { - %courseconfig = %{$settings->{$item}->{'crsconf'}}; - } + $datatable .= ''."\n". + '
    '; + if ($context eq 'domain') { + $datatable .= &mt('Configurable in course'); + } else { + $datatable .= &mt('Configurable for each instance of tool in course'); } - $datatable .= '
    '.&mt('Configurable in course').''; + $datatable .= ''; foreach my $item ('label','title','target','linktext','explanation','append') { my $checked; if ($courseconfig{$item}) { @@ -6617,14 +6817,14 @@ sub print_ltitools { ''.$key.''. ''; + ' value="'.$custom{$key}.'" size="35" />'; } } } $datatable .= ''. ''. - ''; + ''; $datatable .= '
    '."\n"; $itemcount ++; } @@ -6698,18 +6898,27 @@ sub print_ltitools { 'passback' => '7', 'roster' => '300', ); - foreach my $extra ('passback','roster') { + foreach my $extra ('passback','roster','returnurl') { my $onclick = ' onclick="toggleLTITools(this.form,'."'$extra','add'".');"'; $datatable .= '
    '.$lt{$extra}.' '. ''.(' 'x2).''. '
    '. - '
    '; + &mt('Yes').''; + if ($extra eq 'returnurl') { + $datatable .= '
    '. - '
    '.&mt('Configurable in course').''; + '
    '; + if ($context eq 'domain') { + $datatable .= &mt('Configurable in course'); + } else { + $datatable .= &mt('Configurable for each instance of tool in course'); + } + $datatable .= ''; foreach my $item ('label','title','target','linktext','explanation','append') { $datatable .= ' '. ''. - '