--- loncom/interface/lonparmset.pm 2017/07/13 15:29:56 1.578 +++ loncom/interface/lonparmset.pm 2022/02/21 18:04:35 1.604 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Handler to set parameters for assessments # -# $Id: lonparmset.pm,v 1.578 2017/07/13 15:29:56 raeburn Exp $ +# $Id: lonparmset.pm,v 1.604 2022/02/21 18:04:35 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -36,7 +36,8 @@ lonparmset - Handler to set parameters f =head1 SYNOPSIS -lonparmset provides an interface to setting course parameters. +lonparmset provides an interface to setting content parameters in a +course. It contains all the code for the "Content and Problem Settings" UI, except for the helpers parameter.helper and resettimes.helper, and lonhelper.pm, @@ -137,7 +138,7 @@ javascript function 'pjump'. =item print_td() -=item print_usergroups() +=item check_other_groups() =item parm_control_group() @@ -975,10 +976,9 @@ sub storeparm_by_symb_inner { # # @param {string} $value - the parameter value # @param {string} $type - the parameter type -# @param {string} $name - the parameter name (unused) # @param {boolean} $editable - Set to true to get an icon when no value is defined. sub valout { - my ($value,$type,$name,$editable)=@_; + my ($value,$type,$editable)=@_; my $result = ''; # Values of zero are valid. if (! $value && $value ne '0') { @@ -1064,13 +1064,18 @@ sub valout { # @param {string} $marker - identifier for the parameter, "resource id&part_parameter name&level", will be passed as pres_marker when the user submits a change. # @param {string} $return - prefix for the name of the form and field names that will be used to submit the form ('parmform.pres') # @param {string} $call - javascript function to call to submit the form ('psub') -# @param {boolean} $recursive - true if link is for a map/folder where parameter is currently set to be recursive. +# @param {boolean} $recursive - true if link is for a map/folder where parameter is currently set to be recursive. +# @param {string} $extra - optional additional information to send as tenth arg in call to javascript pjump function. sub plink { - my ($type,$dis,$value,$marker,$return,$call,$recursive)=@_; + my ($type,$dis,$value,$marker,$return,$call,$recursive,$extra)=@_; my $winvalue=$value; unless ($winvalue) { - if (&isdateparm($type)) { + if (&isdateparm($type) || (&is_specialstring($type))) { $winvalue=$env{'form.recent_'.$type}; + } elsif ($type eq 'string_yesno') { + if ($env{'form.recent_string'} =~ /^(yes|no)$/i) { + $winvalue=$env{'form.recent_string'}; + } } else { $winvalue=$env{'form.recent_'.(split(/\_/,$type))[0]}; } @@ -1078,16 +1083,16 @@ sub plink { my ($parmname)=((split(/\&/,$marker))[1]=~/\_([^\_]+)$/); my ($hour,$min,$sec,$val)=&preset_defaults($parmname); unless (defined($winvalue)) { $winvalue=$val; } - my $valout = &valout($value,$type,$parmname,1); + my $valout = &valout($value,$type,1); my $unencmarker = $marker; foreach my $item (\$type, \$dis, \$winvalue, \$marker, \$return, \$call, - \$hour, \$min, \$sec) { + \$hour, \$min, \$sec, \$extra) { $$item = &HTML::Entities::encode($$item,'"<>&'); $$item =~ s/\'/\\\'/g; } return ''.($recursive?'' : '').'
'. ''. + .$marker."','".$return."','".$call."','".$hour."','".$min."','".$sec."','".$extra."'".');">'. $valout.'
'. &mt('recursive').'
'; @@ -1106,12 +1111,14 @@ sub page_js { $pjump_def function psub() { + var specstring = /^string_!(yesno|any)/i; if (document.parmform.pres_marker.value!='') { document.parmform.action+='#'+document.parmform.pres_marker.value; var typedef=new Array(); typedef=document.parmform.pres_type.value.split('_'); if (document.parmform.pres_type.value!='') { - if (typedef[0]=='date') { + if ((typedef[0]=='date') || + (specstring.test(document.parmform.pres_type.value))) { eval('document.parmform.recent_'+ document.parmform.pres_type.value+ '.value=document.parmform.pres_value.value;'); @@ -1234,14 +1241,23 @@ function validateParms() { var tailLenient = /\.lenient$/; var patternRelWeight = /^\-?[\d.]+$/; var patternLenientStd = /^(yes|no|default)$/; + var ipRegExp = /^setip/; var ipallowRegExp = /^setipallow_/; var ipdenyRegExp = /^setipdeny_/; + var deeplinkRegExp = /^deeplink_/; + var dlListScopeRegExp = /^deeplink_(state|others|listing|scope)_/; + var dlLinkProtectRegExp = /^deeplink_protect_/; + var dlLtidRegExp = /^deeplink_ltid_/; + var dlLticRegExp = /^deeplink_ltic_/; + var dlKeyRegExp = /^deeplink_key_/; + var dlMenusRegExp = /^deeplink_menus_/; + var dlCollsRegExp = /^deeplink_colls_/; var patternIP = /[\[\]\*\.a-zA-Z\d\-]+/; if ((document.parmform.elements.length != 'undefined') && (document.parmform.elements.length) != 'null') { if (document.parmform.elements.length) { for (i=0; i 0) { + var possdeeplink = document.parmform.elements[i].options[idx].value + possdeeplink = possdeeplink.replace(/^\s+|\s+$/g,''); + if (document.parmform.elements['set_'+identifier].value) { + possdeeplink = ','+possdeeplink; + } + document.parmform.elements['set_'+identifier].value += possdeeplink; + } + } else if (dlLinkProtectRegExp.test(name)) { + if (document.parmform.elements[i].checked) { + var identifier = name.replace(dlLinkProtectRegExp,''); + var posslinkurl = document.parmform.elements[i].value; + posslinkurl = posslinkurl.replace(/^\s+|\s+$/g,''); + if (document.parmform.elements['set_'+identifier].value) { + posslinkurl = ','+posslinkurl; + } + document.parmform.elements['set_'+identifier].value += posslinkurl; + } + } else if (dlLtidRegExp.test(name)) { + var identifier = name.replace(dlLtidRegExp,''); + if (isRadioSet('deeplink_protect_'+identifier,'ltid')) { + var possltid = document.parmform.elements[i].value; + possltid = possltid.replace(/\D+/g,''); + if (possltid.length) { + if (document.parmform.elements['set_'+identifier].value) { + possltid = ':'+possltid; + } + document.parmform.elements['set_'+identifier].value += possltid; + } else { + document.parmform.elements['set_'+identifier].value = ''; + alert("A link type of 'domain LTI launch' was selected but no domain LTI launcher was selected.\nPlease select one, or choose a different supported link type."); + return false; + } + } + } else if (dlLticRegExp.test(name)) { + var identifier = name.replace(dlLticRegExp,''); + if (isRadioSet('deeplink_protect_'+identifier,'ltic')) { + var possltic = document.parmform.elements[i].value; + possltic = possltic.replace(/\D+/g,''); + if (possltic.length) { + if (document.parmform.elements['set_'+identifier].value) { + possltic = ':'+possltic; + } + document.parmform.elements['set_'+identifier].value += possltic; + } else { + document.parmform.elements['set_'+identifier].value = ''; + alert("A link type of 'course LTI launch' was selected but no course LTI launcher was selected.\nPlease select one, or choose a different supported link type."); + return false; + } + } + } else if (dlKeyRegExp.test(name)) { + var identifier = name.replace(dlKeyRegExp,''); + if (isRadioSet('deeplink_protect_'+identifier,'key')) { + var posskey = document.parmform.elements[i].value; + posskey = posskey.replace(/^\s+|\s+$/g,''); + var origlength = posskey.length; + posskey = posskey.replace(/[^a-zA-Z\d_.!@#$%^&*()+=-]/g,''); + var newlength = posskey.length; + if (newlength > 0) { + var change = origlength - newlength; + if (change) { + alert(change+' disallowed character(s) removed from deeplink key'); + } if (document.parmform.elements['set_'+identifier].value) { - possdeny = ','+possdeny; + posskey = ':'+posskey; } - document.parmform.elements['set_'+identifier].value += possdeny; + document.parmform.elements['set_'+identifier].value += posskey; + } else { + document.parmform.elements['set_'+identifier].value = ''; + if (newlength < origlength) { + alert("A link type of 'deep with key' was selected but the key value was blank, after removing disallowed characters.\nPlease enter a key using one or more of: a-zA-Z0-9_.!@#$%^&*()+=-"); + } else { + alert("A link type of 'deep with key' was selected but the key value was blank.\nPlease enter a key."); + } + return false; + } + } + } else if (dlMenusRegExp.test(name)) { + if (document.parmform.elements[i].checked) { + var identifier = name.replace(dlMenusRegExp,''); + var posslinkmenu = document.parmform.elements[i].value; + posslinkmenu = posslinkmenu.replace(/^\s+|\s+$/g,''); + if (posslinkmenu == 'std') { + posslinkmenu = '0'; + if (document.parmform.elements['set_'+identifier].value) { + posslinkmenu = ','+posslinkmenu; + } + document.parmform.elements['set_'+identifier].value += posslinkmenu; } } + } else if (dlCollsRegExp.test(name)) { + var identifier = name.replace(dlCollsRegExp,''); + if (isRadioSet('deeplink_menus_'+identifier,'colls')) { + var posslinkmenu = document.parmform.elements[i].value; + if (document.parmform.elements['set_'+identifier].value) { + posslinkmenu = ','+posslinkmenu; + } + document.parmform.elements['set_'+identifier].value += posslinkmenu; + } } } } @@ -1296,6 +1414,23 @@ function validateParms() { return true; } +function isRadioSet(name,expected) { + var menuitems = document.getElementsByName(name); + var radioLength = menuitems.length; + result = false; + if (radioLength > 1) { + for (var j=0; j map title +# @param {hash reference} - $allmaps_inverted - hash map src -> map pc +# @param {scalar reference} - $reclinks - number of "parameter in effect" cells with link to map where recursive param was set sub print_row { my ($r,$which,$part,$name,$symbp,$rid,$default,$defaulttype,$display,$defbgone, $defbgtwo,$defbgthree,$parmlev,$uname,$udom,$csec,$cgroup,$usersgroups,$noeditgrp, - $readonly)=@_; + $readonly,$recurseup,$maptitles,$allmaps_inverted,$reclinks)=@_; my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; my $courseopt=&Apache::lonnet::get_courseresdata($cnum,$cdom); + my $numlinks = 0; # get the values for the parameter in cascading order # empty levels will remain empty @@ -1469,81 +1672,209 @@ sub print_row { my $thismarker=$which; $thismarker=~s/^parameter\_//; my $mprefix=$rid.'&'.$thismarker.'&'; - my $effective_parm = &valout($outpar[$result],$typeoutpar[$result],$thismarker); - my ($othergrp,$grp_parm,$controlgrp,$effparm_rec); - if ($result == 17 || $result == 11 || $result == 7 || $result == 3) { + my ($parmname)=($thismarker=~/\_([^\_]+)$/); + my ($othergrp,$grp_parm,$controlgrp,$effective_parm,$effparm_rec,$effparm_level, + $eff_groupparm,$recurse_check,$recursinfo,$extra); + if ((ref($recurseup) eq 'ARRAY') && (@{$recurseup} > 0)) { + if ($result eq '') { + $recurse_check = 1; + } elsif (($uname ne '') && ($result > 3)) { + $recurse_check = 1; + } elsif (($cgroup ne '') && ($result > 7)) { + $recurse_check = 1; + } elsif (($csec ne '') && ($result > 11)) { + $recurse_check = 1; + } elsif ($result > 17) { + $recurse_check = 1; + } + if ($recurse_check) { + my $what = $$part{$which}.'.'.$$name{$which}; + my $prefix; + if (($uname ne '') && ($udom ne '')) { + my $useropt = &Apache::lonnet::get_userresdata($uname,$udom); + $prefix = $env{'request.course.id'}; + $recursinfo = &get_recursive($recurseup,$useropt,$what,$prefix); + if (ref($recursinfo) eq 'ARRAY') { + $effparm_rec = 1; + $effparm_level = &mt('user: [_1]',$uname); + } + } + if (($cgroup ne '') && (!$effparm_rec)) { + $prefix = $env{'request.course.id'}.'.['.$cgroup.']'; + $recursinfo = &get_recursive($recurseup,$courseopt,$what,$prefix); + if (ref($recursinfo) eq 'ARRAY') { + $effparm_rec = 1; + $effparm_level = &mt('group: [_1]',$cgroup); + } + } + if (($csec ne '') && (!$effparm_rec)) { + $prefix = $env{'request.course.id'}.'.['.$csec.']'; + $recursinfo = &get_recursive($recurseup,$courseopt,$what,$prefix); + if (ref($recursinfo) eq 'ARRAY') { + $effparm_rec = 1; + $effparm_level = &mt('section: [_1]',$csec); + } + } + if (!$effparm_rec) { + $prefix = $env{'request.course.id'}; + $recursinfo = &get_recursive($recurseup,$courseopt,$what,$prefix); + if (ref($recursinfo) eq 'ARRAY') { + $effparm_rec = 1; + } + } + } + } + if ((!$effparm_rec) && ($result == 17 || $result == 11 || $result == 7 || $result == 3)) { + $effparm_rec = 1; + } + if ((!$effparm_rec) && + (($$name{$which} eq 'encrypturl') || ($$name{$which} eq 'hiddenresource')) && + ($result == 16 || $result == 10 || $result == 6 || $result == 2)) { $effparm_rec = 1; } + if ($parmname eq 'deeplink') { + my ($domltistr,$crsltistr); + my %lti = + &Apache::lonnet::get_domain_lti($env{'course.'.$env{'request.course.id'}.'.domain'}, + 'linkprot'); + if (keys(%lti)) { + foreach my $item (sort { $a <=> $b } (keys(%lti))) { + if (($item =~ /^\d+$/) && (ref($lti{$item}) eq 'HASH')) { + $domltistr .= $item.':'.&escape(&escape($lti{$item}{'name'})).','; + } + } + $domltistr =~ s/,$//; + if ($domltistr) { + $extra = 'ltid_'.$domltistr; + } + } + my %courselti = &Apache::lonnet::get_course_lti($cnum,$cdom); + if (keys(%courselti)) { + foreach my $item (sort { $a <=> $b } keys(%courselti)) { + if (($item =~ /^\d+$/) && (ref($courselti{$item}) eq 'HASH')) { + $crsltistr .= $item.':'.&escape(&escape($courselti{$item}{'name'})).','; + } + } + $crsltistr =~ s/,$//; + if ($crsltistr) { + if ($extra) { + $extra .= '&'; + } + $extra .= 'ltic_'.$crsltistr; + } + } + if ($env{'course.'.$env{'request.course.id'}.'.menucollections'}) { + my @colls; + foreach my $item (split(/;/,$env{'course.'.$env{'request.course.id'}.'.menucollections'})) { + my ($num,$value) = split(/\%/,$item); + if ($num =~ /^\d+$/) { + push(@colls,$num); + } + } + if (@colls) { + if ($extra) { + $extra .= '&'; + } + $extra .= 'menus_'.join(',',@colls); + } + } + } if ($parmlev eq 'general') { if ($uname) { - &print_td($r,4,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly); + &print_td($r,4,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra); } elsif ($cgroup) { - &print_td($r,8,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp,$readonly); + &print_td($r,8,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp,$readonly,'',$extra); } elsif ($csec) { - &print_td($r,12,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly); + &print_td($r,12,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra); } else { - &print_td($r,18,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly); + &print_td($r,18,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra); } } elsif ($parmlev eq 'map') { if ($uname) { - &print_td($r,2,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1); + &print_td($r,2,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra); } elsif ($cgroup) { - &print_td($r,6,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp,$readonly,1); + &print_td($r,6,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp,$readonly,1,$extra); } elsif ($csec) { - &print_td($r,10,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1); + &print_td($r,10,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra); } else { - &print_td($r,16,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1); + &print_td($r,16,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra); } } else { if ($uname) { if (@{$usersgroups} > 1) { - my ($coursereply,$grp_parm,$controlgrp); - ($coursereply,$othergrp,$grp_parm,$controlgrp) = - &print_usergroups($r,$$part{$which}.'.'.$$name{$which}, + (my $coursereply,$othergrp,$grp_parm,$controlgrp,my $grp_is_rec) = + &check_other_groups($$part{$which}.'.'.$$name{$which}, $rid,$cgroup,$defbgone,$usersgroups,$result,$courseopt); - if ($coursereply && $result > 4) { + if (($coursereply) && ($result > 4)) { if (defined($controlgrp)) { if ($cgroup ne $controlgrp) { - $effective_parm = $grp_parm; - $result = 0; + $eff_groupparm = $grp_parm; + undef($result); + undef($effparm_rec); + if ($grp_is_rec) { + $effparm_rec = 1; + } } } } } } - &print_td($r,18,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly); - &print_td($r,16,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1); - &print_td($r,15,'#FFDDDD',$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly); - &print_td($r,14,'#FFDDDD',$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly); - &print_td($r,13,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly); + &print_td($r,18,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra); + &print_td($r,16,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra); + &print_td($r,15,'#FFDDDD',$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra); + &print_td($r,14,'#FFDDDD',$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra); + &print_td($r,13,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra); if ($csec) { - &print_td($r,12,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly); - &print_td($r,10,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1); - &print_td($r,9,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly); + &print_td($r,12,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra); + &print_td($r,10,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra); + &print_td($r,9,$defbgtwo,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra); } if ($cgroup) { - &print_td($r,8,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp,$readonly); - &print_td($r,6,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp,$readonly,1); - &print_td($r,5,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp.$readonly); + &print_td($r,8,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp,$readonly,'',$extra); + &print_td($r,6,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp,$readonly,1,$extra); + &print_td($r,5,$defbgthree,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,$noeditgrp.$readonly,'',$extra); } if ($uname) { if ($othergrp) { $r->print($othergrp); } - &print_td($r,4,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly); - &print_td($r,2,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1); - &print_td($r,1,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly); + &print_td($r,4,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra); + &print_td($r,2,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,1,$extra); + &print_td($r,1,$defbgone,$result,\@outpar,$mprefix,$which,\@typeoutpar,$display,'',$readonly,'',$extra); } - } # end of $parmlev if/else - $r->print(''.$effective_parm. - ($effparm_rec?'
'.&mt('recursive'). - '':'').''); - + if (ref($recursinfo) eq 'ARRAY') { + my $rectitle = &mt('recursive'); + if ((ref($maptitles) eq 'HASH') && (exists($maptitles->{$recursinfo->[2]}))) { + if ((ref($allmaps_inverted) eq 'HASH') && (exists($allmaps_inverted->{$recursinfo->[2]}))) { + $rectitle = &mt('set in: [_1]','"'. + '{$recursinfo->[2]}."',". + "'$parmname','$$part{$which}'".');">'. + $maptitles->{$recursinfo->[2]}.'"'); + + $numlinks ++; + } + } + my ($parmname)=($thismarker=~/\_([^\_]+)$/); + $effective_parm = &valout($recursinfo->[0],$recursinfo->[1]); + $r->print(''.$effective_parm. + '
'.$rectitle.' '. + $effparm_level.''); + } else { + if ($result) { + $effective_parm = &valout($outpar[$result],$typeoutpar[$result]); + } + if ($eff_groupparm) { + $effective_parm = $eff_groupparm; + } + $r->print(''.$effective_parm. + ($effparm_rec?'
'.&mt('recursive'). + '':'').''); + } if ($parmlev eq 'full') { my $sessionval=&Apache::lonnet::EXT('resource.'.$$part{$which}. '.'.$$name{$which},$$symbp{$rid}); @@ -1552,11 +1883,14 @@ sub print_row { $sessionvaltype=$$defaulttype{$which}; } $r->print(''. - &valout($sessionval,$sessionvaltype,$$name{$which}).' '. + &valout($sessionval,$sessionvaltype).' '. ''); } $r->print(''); $r->print("\n"); + if (($numlinks) && (ref($reclinks))) { + $$reclinks = $numlinks; + } } # Prints a cell for table mode. @@ -1576,10 +1910,11 @@ sub print_row { # @param {hash reference} $display - parameter key -> full title for the parameter # @param {boolean} $noeditgrp - true if no edit is allowed for group level parameters # @param {boolean} $readonly -true if editing not allowed. -# @param {boolean} $ismaplevel - true if level is for a map. +# @param {boolean} $ismaplevel - true if level is for a map. +# @param {string} $extra - extra information to pass to plink. sub print_td { my ($r,$which,$defbg,$result,$outpar,$mprefix,$value,$typeoutpar,$display, - $noeditgrp,$readonly,$ismaplevel)=@_; + $noeditgrp,$readonly,$ismaplevel,$extra)=@_; my ($ineffect,$recursive,$currval,$currtype,$currlevel); $ineffect = 0; $currval = $$outpar[$which]; @@ -1618,9 +1953,7 @@ sub print_td { $nolink = 1; } } elsif ($mprefix =~ /availablestudent\&$/) { - if ($which > 4) { - $nolink = 1; - } + $nolink = 1; } elsif ($mprefix =~ /examcode\&$/) { unless ($which == 2) { $nolink = 1; @@ -1629,20 +1962,19 @@ sub print_td { } if ($nolink) { my ($parmname)=((split(/\&/,$mprefix))[1]=~/\_([^\_]+)$/); - $r->print(&valout($currval,$currtype,$parmname)); + $r->print(&valout($currval,$currtype)); } else { $r->print(&plink($currtype, $$display{$value},$currval, - $mprefix.$currlevel,'parmform.pres','psub',$recursive)); + $mprefix.$currlevel,'parmform.pres','psub',$recursive, + $extra)); } $r->print(''."\n"); } -# FIXME: Despite the name, this does not print anything, the $r parameter is unused. # Returns HTML and other info for the cell added when a user is selected # and that user is in several groups. This is the cell with the title "Control by other group". # -# @param {Apache2::RequestRec} $r - the Apache request (unused) # @param {string} $what - parameter part.'.'.parameter name # @param {string} $rid - resource id # @param {string} $cgroup - group name @@ -1650,9 +1982,9 @@ sub print_td { # @param {array reference} $usersgroups - list of groups the user belongs to, if any # @param {integer} $result - level # @param {hash reference} $courseopt - course parameters hash (result of lonnet::get_courseresdata, dump of course's resourcedata.db) -# @returns {Array} - array (parameter value for the other group, HTML for the cell, HTML with the value, name of the other group) -sub print_usergroups { - my ($r,$what,$rid,$cgroup,$defbg,$usersgroups,$result,$courseopt) = @_; +# @returns {Array} - array (parameter value for the other group, HTML for the cell, HTML with the value, name of the other group, true if recursive) +sub check_other_groups { + my ($what,$rid,$cgroup,$defbg,$usersgroups,$result,$courseopt) = @_; my $courseid = $env{'request.course.id'}; my $output; my $symb = &symbcache($rid); @@ -1664,16 +1996,22 @@ sub print_usergroups { &parm_control_group($courseid,$usersgroups,$symbparm,$mapparm, $recurseparm,$what,$courseopt); my $bgcolor = $defbg; - my $grp_parm; + my ($grp_parm,$grp_is_rec); if (($coursereply) && ($cgroup ne $resultgroup)) { + my ($parmname) = ($what =~ /\.([^.]+)$/); if ($result > 3) { $bgcolor = '#AAFFAA'; - $grp_parm = &valout($coursereply,$resulttype,$what); } - $grp_parm = &valout($coursereply,$resulttype,$what); + $grp_parm = &valout($coursereply,$resulttype); $output = ''; if ($resultgroup && $resultlevel) { - $output .= ''.$resultgroup.' ('.$resultlevel.'): '.$grp_parm; + if ($resultlevel eq 'recursive') { + $resultlevel = 'map/folder'; + $grp_is_rec = 1; + } + $output .= ''.$resultgroup.' ('.$resultlevel.'): '.$grp_parm. + ($grp_is_rec?''.&mt('recursive').'':''); + } else { $output .= ' '; } @@ -1681,11 +2019,11 @@ sub print_usergroups { } else { $output .= ' '; } - return ($coursereply,$output,$grp_parm,$resultgroup); + return ($coursereply,$output,$grp_parm,$resultgroup,$grp_is_rec); } # Looks for a group with a defined parameter for given user and parameter. -# Used by print_usergroups. +# Used by check_other_groups. # # @param {string} $courseid - the course id # @param {array reference} $usersgroups - list of groups the user belongs to, if any @@ -1749,11 +2087,22 @@ sub extractResourceInformation { my $uris=shift; my $keyorder=shift; my $defkeytype=shift; + my $pssymb=shift; my $keyordercnt=100; my $navmap = Apache::lonnavmaps::navmap->new(); - my @allres=$navmap->retrieveResources(undef,undef,1,undef,1); + return unless(ref($navmap)); + my @allres; + if ($pssymb ne '') { + my $res = $navmap->getBySymb($pssymb); + if (ref($res)) { + @allres = ($res); + } + } + if (!@allres) { + @allres=$navmap->retrieveResources(undef,undef,1,undef,1); + } foreach my $resource (@allres) { my $id=$resource->id(); my ($mapid,$resid)=split(/\./,$id); @@ -1762,23 +2111,27 @@ sub extractResourceInformation { my $srcf=$resource->src(); $srcf=~/\.(\w+)$/; $$typep{$id}=$1; + my $toolsymb; + if ($srcf =~ /ext\.tool$/) { + $toolsymb = $resource->symb(); + } $$keyp{$id}=''; $$uris{$id}=$srcf; - foreach my $key (split(/\,/,&Apache::lonnet::metadata($srcf,'allpossiblekeys'))) { + foreach my $key (split(/\,/,&Apache::lonnet::metadata($srcf,'allpossiblekeys',$toolsymb))) { next if ($key!~/^parameter_/); # Hidden parameters - next if (&Apache::lonnet::metadata($srcf,$key.'.hidden') eq 'parm'); + next if (&Apache::lonnet::metadata($srcf,$key.'.hidden',$toolsymb) eq 'parm'); # # allparms is a hash of parameter names # - my $name=&Apache::lonnet::metadata($srcf,$key.'.name'); + my $name=&Apache::lonnet::metadata($srcf,$key.'.name',$toolsymb); if (!exists($$allparms{$name}) || $$allparms{$name} =~ m/^\s*$/ ) { my ($display,$parmdis); $display = &standard_parameter_names($name); if ($display eq '') { - $display= &Apache::lonnet::metadata($srcf,$key.'.display'); + $display= &Apache::lonnet::metadata($srcf,$key.'.display',$toolsymb); $parmdis = $display; $parmdis =~ s/\s*\[Part.*$//g; } else { @@ -1787,14 +2140,14 @@ sub extractResourceInformation { $$allparms{$name}=$parmdis; if (ref($defkeytype)) { $$defkeytype{$name}= - &Apache::lonnet::metadata($srcf,$key.'.type'); + &Apache::lonnet::metadata($srcf,$key.'.type',$toolsymb); } } # # allparts is a hash of all parts # - my $part= &Apache::lonnet::metadata($srcf,$key.'.part'); + my $part= &Apache::lonnet::metadata($srcf,$key.'.part',$toolsymb); $$allparts{$part} = &mt('Part: [_1]',$part); # # Remember all keys going with this resource @@ -1835,6 +2188,29 @@ sub extractResourceInformation { } } +sub get_recursive { + my ($recurseup,$resdata,$what,$prefix) = @_; + if ((ref($resdata) eq 'HASH') && (ref($recurseup) eq 'ARRAY')) { + foreach my $item (@{$recurseup}) { + my $norecursechk=$prefix.'.'.$item.'___(all).'.$what; + if (defined($resdata->{$norecursechk})) { + if ($what =~ /\.(encrypturl|hiddenresource)$/) { + my $type = $resdata->{$norecursechk.'.type'}; + return [$resdata->{$norecursechk},$type,$item]; + } else { + last; + } + } + my $recursechk=$prefix.'.'.$item.'___(rec).'.$what; + if (defined($resdata->{$recursechk})) { + my $type = $resdata->{$recursechk.'.type'}; + return [$resdata->{$recursechk},$type,$item]; + } + } + } + return; +} + # Tells if a parameter type is a date. # @@ -1845,16 +2221,19 @@ sub isdateparm { return (($type=~/^date/) && (!($type eq 'date_interval'))); } +# Determine if parameter type is specialized string type (i.e., +# not just string or string_yesno. + +sub is_specialstring { + my $type=shift; + return (($type=~/^string_/) && ($type ne 'string_yesno')); +} + # Prints the HTML and Javascript to select parameters, with various shortcuts. -# FIXME: remove unused parameters # -# @param {Apache2::RequestRec} $r - the Apache request (unused) -# @param {hash reference} $allparms - hash parameter name -> parameter title -# @param {array reference} $pscat - list of selected parameter names (unused) -# @param {hash reference} $keyorder - hash parameter key -> appearance rank (unused) +# @param {Apache2::RequestRec} $r - the Apache request sub parmmenu { - my ($r,$allparms,$pscat,$keyorder)=@_; - my $tempkey; + my ($r)=@_; $r->print(< // print('
'); - &shortCuts($r,$allparms,$pscat,$keyorder); + &shortCuts($r); $r->print('
'); } @@ -1985,6 +2364,7 @@ sub lookUpTableParameter { 'buttonshide' => 'hiding', 'turnoffeditor' => 'hiding', 'encrypturl' => 'hiding', + 'deeplink' => 'hiding', 'randomorder' => 'high_level_randomization', 'randompick' => 'high_level_randomization', 'available' => 'slots', @@ -2000,7 +2380,7 @@ sub lookUpTableParameter { 'lenient' => 'grading', 'retrypartial' => 'tries', 'discussvote' => 'misc', - 'examcode' => 'high_level_randomization', + 'examcode' => 'high_level_randomization', ); } @@ -2112,14 +2492,10 @@ sub parmboxes { } # Prints HTML with shortcuts to select groups of parameters in one click, or deselect all. -# FIXME: remove unused parameters # # @param {Apache2::RequestRec} $r - the Apache request -# @param {hash reference} $allparms - hash parameter name -> parameter title (unused) -# @param {array reference} $pscat - list of selected parameter names (unused) -# @param {hash reference} $keyorder - hash parameter key -> appearance rank (unused) sub shortCuts { - my ($r,$allparms,$pscat,$keyorder)=@_; + my ($r)=@_; # Parameter Selection $r->print( @@ -2198,9 +2574,37 @@ sub partmenu { sub usermenu { my ($r,$uname,$id,$udom,$csec,$cgroup,$parmlev,$usersgroups,$pssymb)=@_; my $chooseopt=&Apache::loncommon::select_dom_form($udom,'udom').' '. - &Apache::loncommon::selectstudent_link('parmform','uname','udom'); - my $selscript=&Apache::loncommon::studentbrowser_javascript(); + &Apache::loncommon::selectstudent_link('parmform','uname','udom','condition'). + &Apache::lonhtmlcommon::scripttag(<'. + $stuonly.'  '. + ''; my $sections=''; my %sectionhash = &Apache::loncommon::get_sections(); @@ -2209,7 +2613,7 @@ sub usermenu { if (($pssymb) || &Apache::lonnet::allowed('mdg',$env{'request.course.id'})) { %grouphash = &Apache::longroup::coursegroups(); } elsif ($env{'request.course.groups'} ne '') { - map { $grouphash{$_} = 1; } split(/,/,$env{'request.course.groups'}); + map { $grouphash{$_} = 1; } split(/:/,$env{'request.course.groups'}); } my $g_s_header=''; @@ -2267,7 +2671,7 @@ function group_or_section(caller) { } if (%grouphash) { - $groups=&mt('Group:').' '). '" name="recent_'.$item.'" />'); @@ -3105,7 +3613,7 @@ ENDPARMSELSCRIPT # Step 2 $r->print(&Apache::lonhtmlcommon::topic_bar(2,&mt('Parameter Specification'),'parmstep2')); - &displaymenu($r,\%allparms,\@pscat,\@psprt,\%keyorder,'parmmenuscroll'); + &displaymenu($r,\%allparms,\@pscat,\%keyorder,'parmmenuscroll'); # Step 3 $r->print(&Apache::lonhtmlcommon::topic_bar(3,&mt('User Specification (optional)'),'parmstep3')); @@ -3264,7 +3772,6 @@ ENDTABLEHEADFOUR foreach my $rid (@ids) { my ($inmapid)=($rid=~/\.(\d+)$/); - if ((!$pssymb && (($pschp eq 'all') || ($allmaps{$pschp} eq $mapp{$rid}))) || @@ -3294,19 +3801,23 @@ ENDTABLEHEADFOUR my %type= (); my %default=(); my $uri=&Apache::lonnet::declutter($uris{$rid}); + my $toolsymb; + if ($uri =~ /ext\.tool$/) { + $toolsymb = $symbp{$rid}; + } my $filter=$env{'form.filter'}; foreach my $tempkeyp (&keysplit($keyp{$rid})) { if (grep $_ eq $tempkeyp, @catmarker) { - my $parmname=&Apache::lonnet::metadata($uri,$tempkeyp.'.name'); + my $parmname=&Apache::lonnet::metadata($uri,$tempkeyp.'.name',$toolsymb); # We may only want certain parameters listed if ($filter) { unless ($filter=~/\Q$parmname\E/) { next; } } $name{$tempkeyp}=$parmname; - $part{$tempkeyp}=&Apache::lonnet::metadata($uri,$tempkeyp.'.part'); + $part{$tempkeyp}=&Apache::lonnet::metadata($uri,$tempkeyp.'.part',$toolsymb); - my $parmdis=&Apache::lonnet::metadata($uri,$tempkeyp.'.display'); + my $parmdis=&Apache::lonnet::metadata($uri,$tempkeyp.'.display',$toolsymb); if ($allparms{$name{$tempkeyp}} ne '') { my $identifier; if ($parmdis =~ /(\s*\[Part.*)$/) { @@ -3318,15 +3829,20 @@ ENDTABLEHEADFOUR } unless ($display{$tempkeyp}) { $display{$tempkeyp}=''; } $display{$tempkeyp}.=' ('.$name{$tempkeyp}.')'; - $default{$tempkeyp}=&Apache::lonnet::metadata($uri,$tempkeyp); - $type{$tempkeyp}=&Apache::lonnet::metadata($uri,$tempkeyp.'.type'); - $thistitle=&Apache::lonnet::metadata($uri,$tempkeyp.'.title'); + $default{$tempkeyp}=&Apache::lonnet::metadata($uri,$tempkeyp,$toolsymb); + $type{$tempkeyp}=&Apache::lonnet::metadata($uri,$tempkeyp.'.type',$toolsymb); + $thistitle=&Apache::lonnet::metadata($uri,$tempkeyp.'.title',$toolsymb); } } my $totalparms=scalar(keys(%name)); if ($totalparms>0) { my $firstrow=1; my $title=&Apache::lonnet::gettitle($symbp{$rid}); + my $navmap = Apache::lonnavmaps::navmap->new(); + my @recurseup; + if (ref($navmap) && $mapp{$rid}) { + @recurseup = $navmap->recurseup_maps($mapp{$rid}); + } $r->print(''. @@ -3358,7 +3874,9 @@ ENDTABLEHEADFOUR &print_row($r,$item,\%part,\%name,\%symbp,$rid,\%default, \%type,\%display,$defbgone,$defbgtwo, $defbgthree,$parmlev,$uname,$udom,$csec, - $cgroup,\@usersgroups,$noeditgrp,$readonly); + $cgroup,\@usersgroups,$noeditgrp,$readonly, + \@recurseup,\%maptitles,\%allmaps_inverted, + \$numreclinks); } } } @@ -3404,6 +3922,11 @@ ENDTABLEHEADFOUR if ($map eq $mapid) { my $uri=&Apache::lonnet::declutter($uris{$rid}); + my $toolsymb; + if ($uri =~ /ext\.tool$/) { + $toolsymb = $symbp{$rid}; + } + # $r->print("Keys: $keyp{$rid}
\n"); #-------------------------------------------------------------------- @@ -3419,8 +3942,8 @@ ENDTABLEHEADFOUR if ((grep $_ eq $fullkeyp, @catmarker) &&(!$name{$tempkeyp})) { $part{$tempkeyp}="0"; - $name{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp.'.name'); - my $parmdis=&Apache::lonnet::metadata($uri,$fullkeyp.'.display'); + $name{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp.'.name',$toolsymb); + my $parmdis=&Apache::lonnet::metadata($uri,$fullkeyp.'.display',$toolsymb); if ($allparms{$name{$tempkeyp}} ne '') { my $identifier; if ($parmdis =~ /(\s*\[Part.*)$/) { @@ -3433,8 +3956,8 @@ ENDTABLEHEADFOUR unless ($display{$tempkeyp}) { $display{$tempkeyp}=''; } $display{$tempkeyp}.=' ('.$name{$tempkeyp}.')'; $display{$tempkeyp} =~ s/_\w+_/_0_/; - $default{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp); - $type{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp.'.type'); + $default{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp,$toolsymb); + $type{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp.'.type',$toolsymb); } } # end loop through keys } @@ -3476,12 +3999,23 @@ ENDTABLEHEADFOUR .&Apache::loncommon::end_data_table_header_row() ); + my $navmap = Apache::lonnavmaps::navmap->new(); + my @recurseup; + if (ref($navmap)) { + my $mapres = $navmap->getByMapPc($mapid); + if (ref($mapres)) { + @recurseup = $navmap->recurseup_maps($mapres->src()); + } + } + + foreach my $item (&keysinorder(\%name,\%keyorder)) { $r->print(&Apache::loncommon::start_data_table_row()); &print_row($r,$item,\%part,\%name,\%symbp,$mapid,\%default, \%type,\%display,$defbgone,$defbgtwo,$defbgthree, $parmlev,$uname,$udom,$csec,$cgroup,'',$noeditgrp, - $readonly); + $readonly,\@recurseup,\%maptitles,\%allmaps_inverted, + \$numreclinks); } $r->print(&Apache::loncommon::end_data_table().'

' .'' @@ -3508,6 +4042,10 @@ ENDTABLEHEADFOUR my $rid = $id; my $uri=&Apache::lonnet::declutter($uris{$rid}); + my $toolsymb; + if ($uri =~ /ext\.tool$/) { + $toolsymb = $symbp{$rid}; + } #-------------------------------------------------------------------- # @catmarker contains list of all possible parameters including part #s @@ -3521,8 +4059,8 @@ ENDTABLEHEADFOUR $tempkeyp =~ s/_\w+_/_0_/; if ((grep $_ eq $fullkeyp, @catmarker) &&(!$name{$tempkeyp})) { $part{$tempkeyp}="0"; - $name{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp.'.name'); - my $parmdis=&Apache::lonnet::metadata($uri,$fullkeyp.'.display'); + $name{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp.'.name',$toolsymb); + my $parmdis=&Apache::lonnet::metadata($uri,$fullkeyp.'.display',$toolsymb); if ($allparms{$name{$tempkeyp}} ne '') { my $identifier; if ($parmdis =~ /(\s*\[Part.*)$/) { @@ -3535,8 +4073,8 @@ ENDTABLEHEADFOUR unless ($display{$tempkeyp}) { $display{$tempkeyp}=''; } $display{$tempkeyp}.=' ('.$name{$tempkeyp}.')'; $display{$tempkeyp} =~ s/_\w+_/_0_/; - $default{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp); - $type{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp.'.type'); + $default{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp,$toolsymb); + $type{$tempkeyp}=&Apache::lonnet::metadata($uri,$fullkeyp.'.type',$toolsymb); } } # end loop through keys } # end loop through ids @@ -3581,6 +4119,25 @@ ENDMAPONE } # end of $parmlev eq general } $r->print(''); + if ($numreclinks) { + $r->print(<<"END"); +
+ + + + +
+ +END + } &endSettingsScreen($r); $r->print(&Apache::loncommon::end_page()); } # end sub assessparms @@ -3666,7 +4223,7 @@ sub readdata { # Stores parameter data, using form parameters directly. # # Uses the following form parameters. The variable part in the names is a resourcedata key (except for a modification for user data). -# set_* (except settext, setipallow, setipdeny) - set a parameter value +# set_* (except settext, setipallow, setipdeny, setdeeplink) - set a parameter value # del_* - remove a parameter # datepointer_* - set a date parameter (value is key_* refering to a set of other form parameters) # dateinterval_* - set a date interval parameter (value refers to more form parameters) @@ -3699,7 +4256,7 @@ sub storedata { my $cmd=$1; my $thiskey=$2; my ($altkey,$recursive,$tkey,$tkeyrec,$tkeynonrec); - next if ($cmd eq 'rec' || $cmd eq 'settext' || $cmd eq 'setipallow' || $cmd eq 'setipdeny'); + next if ($cmd eq 'rec' || $cmd eq 'settext' || $cmd eq 'setipallow' || $cmd eq 'setipdeny' || $cmd eq 'setdeeplink'); if ((($cmd eq 'set') || ($cmd eq 'datepointer') || ($cmd eq 'dateinterval') || ($cmd eq 'del')) && ($thiskey =~ /(?:sequence|page)\Q___(all)\E/)) { unless ($thiskey =~ /(encrypturl|hiddenresource)$/) { @@ -3730,8 +4287,8 @@ sub storedata { $text = &mt('Saved modified parameter for'); if ($typeof eq 'string_questiontype') { $name = 'type'; - } elsif ($typeof eq 'string_lenient') { - $name = 'lenient'; + } elsif (($typeof eq 'string_lenient') || ($typeof eq 'string_deeplink')) { + ($name) = ($typeof =~ /^string_(lenient|deeplink)$/); my $stringmatch = &standard_string_matches($typeof); if (ref($stringmatch) eq 'ARRAY') { foreach my $item (@{$stringmatch}) { @@ -4110,6 +4667,7 @@ sub listdata { $tableopen=0; my $foundkeys=0; my %keyorder=&standardkeyorder(); + my $readonlyall = $readonly; my ($secidx,%grouphash); if (($env{'request.course.sec'} ne '') && ($caller eq 'overview')) { @@ -4117,7 +4675,7 @@ sub listdata { if (&Apache::lonnet::allowed('mdg',$env{'request.course.id'})) { %grouphash = &Apache::longroup::coursegroups(); } elsif ($env{'request.course.groups'} ne '') { - map { $grouphash{$_} = 1; } split(/,/,$env{'request.course.groups'}); + map { $grouphash{$_} = 1; } split(/:/,$env{'request.course.groups'}); } } @@ -4171,6 +4729,8 @@ sub listdata { my ($middle,$part,$name)= ($thiskey=~/^$env{'request.course.id'}\.(?:(.+)\.)*([\w\s\-]+)\.(\w+)$/); my $section=&mt('All Students'); + $readonly = $readonlyall; + my $userscope; my $showval = $$resourcedata{$thiskey}; if ($middle=~/^\[(.*)\]/) { my $issection=$1; @@ -4184,6 +4744,7 @@ sub listdata { } } $section=&mt('User').": ".&Apache::loncommon::plainname($stuname,$studom); + $userscope = 1; } else { if (($env{'request.course.sec'} ne '') && ($caller eq 'overview')) { if (exists($grouphash{$issection})) { @@ -4281,8 +4842,13 @@ sub listdata { ''.&mt($parmitem). ''); unless ($readonly) { + my $disabled; + if (($name eq 'availablestudent') && + (($showval eq '') || ($userscope))) { + $disabled = ' disabled="disabled"'; + } $r->print(''); + $thiskey.'"'.$disabled.' />'); } $r->print(''); $foundkeys++; @@ -4310,6 +4876,9 @@ sub listdata { $r->print(&date_interval_selector($thiskey,$name, $showval,$readonly)); } elsif ($thistype =~ m/^string/) { + if ($name eq 'availablestudent') { + $readonly = 1; + } $r->print(&string_selector($thistype,$thiskey, $showval,$name,$readonly)); } else { @@ -4462,6 +5031,215 @@ sub string_ip_selector { return $output; } +sub string_deeplink_selector { + my ($thiskey, $showval, $readonly) = @_; + my (@components,%values,@current,%titles,%options,%optiontext,%defaults, + %selectnull,%domlti,%crslti,@possmenus); + @components = ('state','others','listing','scope','protect','menus'); + %titles = &Apache::lonlocal::texthash ( + state => 'Access status', + others => 'Hide other resources', + listing => 'In Contents and/or Gradebook', + scope => 'Access scope for link', + protect => 'Link protection', + menus => 'Menu Items Displayed', + ); + %options = ( + state => ['only','off','both'], + others => ['hide','unhide'], + listing => ['full','absent','grades','details','datestatus'], + scope => ['res','map','rec'], + protect => ['none','key','ltid','ltic'], + menus => ['std','colls'], + ); + %optiontext = &Apache::lonlocal::texthash ( + only => 'deep only', + off => 'deeplink off', + both => 'regular + deep', + hide => 'Hidden', + unhide => 'Unhidden', + full => 'Listed (linked) in both', + absent => 'Not listed', + grades => 'Listed in grades only', + details => 'Listed (unlinked) in both', + datestatus => 'Listed (unlinked) inc. status in both', + res => 'resource only', + map => 'enclosing map/folder', + rec => 'recursive map/folder', + none => 'not in use', + key => 'key access', + ltic => 'LTI access (course)', + ltid => 'LTI access (domain)' , + std => 'Standard (all menus)', + colls => 'Numbered collection', + ); + %selectnull = &Apache::lonlocal::texthash ( + ltic => 'Select Launcher', + ltid => 'Select Launcher', + colls => 'Select', + ); + if ($showval =~ /,/) { + %values=(); + @current = split(/,/,$showval); + ($values{'state'}) = ($current[0] =~ /^(only|off|both)$/); + ($values{'others'}) = ($current[1] =~ /^(hide|unhide)$/); + ($values{'listing'}) = ($current[2] =~ /^(full|absent|grades|details|datestatus)$/); + ($values{'scope'}) = ($current[3] =~ /^(res|map|rec)$/); + ($values{'protect'}) = ($current[4] =~ /^(key:[a-zA-Z\d_.!\@#\$%^&*()+=-]+|ltic:\d+|ltid:\d+)$/); + ($values{'menus'}) = ($current[5] =~ /^(\d+)$/); + } else { + $defaults{'state'} = 'off', + $defaults{'others'} = 'unhide', + $defaults{'listing'} = 'full'; + $defaults{'scope'} = 'res'; + $defaults{'protect'} = 'none'; + $defaults{'menus'} = '0'; + } + my $disabled; + if ($readonly) { + $disabled=' disabled="disabled"'; + } + my %courselti = + &Apache::lonnet::get_course_lti($env{'course.'.$env{'request.course.id'}.'.num'}, + $env{'course.'.$env{'request.course.id'}.'.domain'}); + foreach my $item (keys(%courselti)) { + if (ref($courselti{$item}) eq 'HASH') { + $crslti{$item} = $courselti{$item}{'name'}; + } + } + my %lti = + &Apache::lonnet::get_domain_lti($env{'course.'.$env{'request.course.id'}.'.domain'}, + 'linkprot'); + foreach my $item (keys(%lti)) { + if (($item =~ /^\d+$/) && (ref($lti{$item}) eq 'HASH')) { + $domlti{$item} = $lti{$item}{'name'}; + } + } + if ($env{'course.'.$env{'request.course.id'}.'.menucollections'}) { + foreach my $item (split(/;/,$env{'course.'.$env{'request.course.id'}.'.menucollections'})) { + my ($num,$value) = split(/\%/,$item); + if ($num =~ /^\d+$/) { + push(@possmenus,$num); + } + } + } + + my $output = ''; + foreach my $item (@components) { + $output .= ''; + } + $output .= ''; + foreach my $item (@components) { + $output .= ''; + } + $output .= '
'.$titles{$item}.'
'; + if (($item eq 'protect') || ($item eq 'menus')) { + my $selected = $values{$item}; + foreach my $option (@{$options{$item}}) { + if ($item eq 'protect') { + if ($option eq 'ltid') { + next unless (keys(%domlti)); + } elsif ($option eq 'ltic') { + next unless (keys(%crslti)); + } + } elsif (($item eq 'menus') && ($option eq 'colls')) { + next unless (@possmenus); + } + my $checked; + if ($item eq 'menus') { + if (($selected =~ /^\d+$/) && (@possmenus) && + (grep(/^\Q$selected\E$/,@possmenus))) { + if ($option eq 'colls') { + $checked = ' checked="checked"'; + } + } elsif (($option eq 'std') && ($selected == 0) && ($selected ne '')) { + $checked = ' checked="checked"'; + } + } elsif ($selected =~ /^\Q$option\E/) { + $checked = ' checked="checked"'; + } + my $onclick; + unless ($readonly) { + my $esc_key = &js_escape($thiskey); + $onclick = ' onclick="toggleDeepLink(this.form,'."'$item','$esc_key'".');"'; + } + $output .= ''; + if (($item eq 'protect') && ($option eq 'key')) { + my $visibility="hidden"; + my $currkey; + if ($checked) { + $visibility = "text"; + $currkey = (split(/\:/,$values{$item}))[1]; + } + $output .= ' '. + ''; + } elsif (($option eq 'ltic') || ($option eq 'ltid') || ($option eq 'colls')) { + my $display="none"; + my ($current,$blankcheck,@possibles); + if ($checked) { + $display = 'inline-block'; + if (($option eq 'ltic') || ($option eq 'ltid')) { + $current = (split(/\:/,$selected))[1]; + } else { + $current = $selected; + } + } else { + $blankcheck = ' selected="selected"'; + } + if ($option eq 'ltid') { + @possibles = keys(%domlti); + } elsif ($option eq 'ltic') { + @possibles = keys(%crslti); + } else { + @possibles = @possmenus; + } + $output .= '
 
'; + } + $output .= '
'; + } + } else { + my $selected = $values{$item}; + my $defsel; + if ($selected eq '') { + $defsel = ' selected="selected"'; + } + $output .= ''; + } + $output .= '
'."\n"; + return $output; +} + { # block using some constants related to parameter types (overview mode) @@ -4495,8 +5273,11 @@ my %strings = ['no','No']], 'string_ip' => [['_allowfrom_','Hostname(s), or IP(s) from which access is allowed'], - ['_denyfrom_',], 'Hostname(s) or IP(s) from which access is disallowed'], - ); + ['_denyfrom_','Hostname(s) or IP(s) from which access is disallowed']], + 'string_deeplink' + => [['on','Set choices for link protection, resource listing, access scope, and shown menu items']], + ); + my %stringmatches = ( 'string_lenient' @@ -4504,6 +5285,8 @@ my %stringmatches = ( 'string_ip' => [['_allowfrom_','[^\!]+'], ['_denyfrom_','\!']], + 'string_deeplink' + => [['on','^(only|off|both)\,(hide|unhide)\,(full|absent|grades|details|datestatus)\,(res|map|rec)\,(none|key\:\w+|ltic\:\d+|ltid\:\d+)\,(\d+|)$']], ); my %stringtypes = ( @@ -4513,6 +5296,7 @@ my %stringtypes = ( discussvote => 'string_discussvote', examcode => 'string_examcode', acc => 'string_ip', + deeplink => 'string_deeplink', ); # Returns the possible values and titles for a given string type, or undef if there are none. @@ -4572,6 +5356,7 @@ sub string_selector { ($thistype eq 'string_lenient') || ($thistype eq 'string_discussvote') || ($thistype eq 'string_ip') || + ($thistype eq 'string_deeplink') || ($name eq 'retrypartial')) { my ($got_chostname,$chostname,$cmajor,$cminor); foreach my $possibilities (@{ $strings{$thistype} }) { @@ -4610,6 +5395,8 @@ sub string_selector { if ($thistype eq 'string_ip') { return &string_ip_selector($thiskey,$showval,$readonly); + } elsif ($thistype eq 'string_deeplink') { + return &string_deeplink_selector($thiskey,$showval,$readonly); } my ($result,$disabled); @@ -4965,9 +5752,22 @@ sub oldversion_warning { # @param {integer} $shift - time to shift, in seconds # @returns {string} - error name or 'ok' sub dateshift { - my ($shift)=@_; + my ($shift,$numchanges)=@_; my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'}; my $crs = $env{'course.'.$env{'request.course.id'}.'.num'}; + my $sec = $env{'request.course.sec'}; + my $secgrpregex; + if ($sec ne '') { + my @groups; + if ($env{'request.course.groups'} ne '') { + @groups = split(/:/,$env{'request.course.groups'}); + } + if (@groups) { + $secgrpregex = '(?:'.join('|',($sec,@groups)).')'; + } else { + $secgrpregex = $sec; + } + } my %data=&Apache::lonnet::dump('resourcedata',$dom,$crs); # ugly retro fix for broken version of types foreach my $key (keys(%data)) { @@ -4982,7 +5782,11 @@ sub dateshift { # go through all parameters and look for dates foreach my $key (keys(%data)) { if ($data{$key.'.type'}=~/^date_(start|end)$/) { + if ($sec ne '') { + next unless ($key =~ /^$env{'request.course.id'}\.\[$secgrpregex\]\./); + } my $newdate=$data{$key}+$shift; + $$numchanges ++; $storecontent{$key}=$newdate; } } @@ -5024,6 +5828,7 @@ sub newoverview { &validateparms_js()."\n". &ipacc_boxes_js()."\n". &done_proctor_js()."\n". + &deeplink_js()."\n". '// ]]> '; @@ -5088,7 +5893,7 @@ ENDOVER &extractResourceInformation(\@ids, \%typep,\%keyp, \%allparms, \%allparts, \%allmaps, \%mapp, \%symbp,\%maptitles,\%uris, - \%keyorder,\%defkeytype); + \%keyorder,\%defkeytype,$pssymb); if (grep {$_ eq 'all'} (@psprt)) { @psprt = keys(%allparts); @@ -5110,7 +5915,7 @@ ENDOVER $r->print('
'); $r->print('
'); - &displaymenu($r,\%allparms,\@pscat,\%keyorder); # FIXME: wrong parameters, could make keysindisplayorderCategory crash because $keyorder is undefined + &displaymenu($r,\%allparms,\@pscat,\%keyorder); $r->print(&Apache::lonhtmlcommon::start_pick_box()); $r->print(&Apache::lonhtmlcommon::row_title(&mt('Select Parts to View'))); my $sectionselector = §ionmenu(\@selected_sections); @@ -5245,6 +6050,7 @@ sub overview { &validateparms_js()."\n". &ipacc_boxes_js()."\n". &done_proctor_js()."\n". + &deeplink_js()."\n". '// ]]>'."\n". ''."\n"; &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=setoverview', @@ -5356,10 +6162,8 @@ ENDOVER $r->print(&mt('All users')); } elsif ($data{'scope_type'} eq 'user') { $r->print(&mt('User: [_1]',join(':',@{$data{'scope'}}))); - } elsif ($data{'scope_type'} eq 'section') { - $r->print(&mt('Section: [_1]',$data{'scope'})); - } elsif ($data{'scope_type'} eq 'group') { - $r->print(&mt('Group: [_1]',$data{'scope'})); + } elsif ($data{'scope_type'} eq 'secgroup') { + $r->print(&mt('Group/Section: [_1]',$data{'scope'})); } $r->print('
'); if ($data{'realm_type'} eq 'all') { @@ -5394,9 +6198,21 @@ sub date_shift_one { my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'}; my $crs = $env{'course.'.$env{'request.course.id'}.'.num'}; my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'}; - + my $sec = $env{'request.course.sec'}; &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=dateshift1&timebase='.$env{'form.timebase'}, text=>"Shifting Dates"}); + my $submit_text = &mt('Shift all dates accordingly'); + if ($sec ne '') { + my @groups; + if ($env{'request.course.groups'} ne '') { + @groups = split(/:/,$env{'request.course.groups'}); + } + if (@groups) { + $submit_text = &mt("Shift dates set just for your section/group(s), accordingly"); + } else { + $submit_text = &mt("Shift dates set just for your section, accordingly"); + } + } my $start_page=&Apache::loncommon::start_page('Shift Dates'); my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Shift'); $r->print($start_page.$breadcrumbs); @@ -5412,7 +6228,7 @@ sub date_shift_one { ''. ''. ''. - ''); + ''); &endSettingsScreen($r); $r->print(&Apache::loncommon::end_page()); } @@ -5424,6 +6240,7 @@ sub date_shift_two { my ($r) = @_; my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'}; my $crs = $env{'course.'.$env{'request.course.id'}.'.num'}; + my $sec = $env{'request.course.sec'}; my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'}; &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=dateshift1&timebase='.$env{'form.timebase'}, text=>"Shifting Dates"}); @@ -5432,14 +6249,47 @@ sub date_shift_two { $r->print($start_page.$breadcrumbs); &startSettingsScreen($r,'parmset',$crstype); my $timeshifted=&Apache::lonhtmlcommon::get_date_from_form('timeshifted'); - $r->print('

'.&mt('Shift Dates').'

'. - '

'.&mt('Shifting all dates such that [_1] becomes [_2]', - &Apache::lonlocal::locallocaltime($env{'form.timebase'}), - &Apache::lonlocal::locallocaltime($timeshifted)).'

'); + $r->print('

'.&mt('Shift Dates').'

'); + if ($sec ne '') { + my @groups; + if ($env{'request.course.groups'} ne '') { + @groups = split(/:/,$env{'request.course.groups'}); + } + if (@groups) { + $r->print('

'. + &mt("Shift dates set just for your section/group(s), such that [_1] becomes [_2]", + &Apache::lonlocal::locallocaltime($env{'form.timebase'}), + &Apache::lonlocal::locallocaltime($timeshifted)). + '

'); + } else { + $r->print('

'. + &mt("Shift dates set just for your section, such that [_1] becomes [_2]", + &Apache::lonlocal::locallocaltime($env{'form.timebase'}), + &Apache::lonlocal::locallocaltime($timeshifted)). + '

'); + } + } else { + $r->print('

'.&mt('Shifting all dates such that [_1] becomes [_2]', + &Apache::lonlocal::locallocaltime($env{'form.timebase'}), + &Apache::lonlocal::locallocaltime($timeshifted)). + '

'); + } my $delta=$timeshifted-$env{'form.timebase'}; - &dateshift($delta); + my $numchanges = 0; + my $result = &dateshift($delta,\$numchanges); + if ($result eq 'ok') { + $r->print( + &Apache::lonhtmlcommon::confirm_success(&mt('Completed shifting of [quant,_1,date setting]', + $numchanges))); + } elsif ($result eq 'con_delayed') { + $r->print( + &Apache::lonhtmlcommon::confirm_success(&mt('Queued shifting of [quant,_1,date setting]', + $numchanges))); + } else { + $r->print( + &Apache::lonhtmlcommon::confirm_success(&mt('An error occurred attempting to shift dates'),1)); + } $r->print( - &Apache::lonhtmlcommon::confirm_success(&mt('Done')). '

'. &Apache::lonhtmlcommon::actionbox( [''.&mt('Content and Problem Settings').''])); @@ -5466,8 +6316,7 @@ sub parse_key { $data{'scope_type'} = 'user'; $data{'scope'} = [$1,$2]; } else { - #FIXME check for group scope - $data{'scope_type'} = 'section'; + $data{'scope_type'} = 'secgroup'; } $middle=~s/^\[(.*)\]//; } @@ -5813,7 +6662,7 @@ sub continue { my $output; $output .= '
'; $output .= ''; - $output .= ''; + $output .= ''; return ($output); } @@ -5841,7 +6690,10 @@ sub addmetafield { my $put_result = &Apache::lonnet::put('environment', {'metadata.'.$meta_field.'.options'=>$options},$dom,$crs); - $r->print('Undeleted Metadata Field '.$env{'course.'.$env{'request.course.id'}.'.metadata.'.$meta_field.'.added'}." with result ".$put_result.'
'); + $r->print(&mt('Undeleted Metadata Field [_1] with result [_2]', + ''.$env{'course.'.$env{'request.course.id'}.'.metadata.'.$meta_field.'.added'}. + '',$put_result). + '
'); } $r->print(&continue()); } elsif (exists($env{'form.fieldname'})) { @@ -5853,24 +6705,32 @@ sub addmetafield { {'metadata.'.$meta_field.'.values'=>"", 'metadata.'.$meta_field.'.added'=>"$display_field", 'metadata.'.$meta_field.'.options'=>""},$dom,$crs); - $r->print('Added new Metadata Field '.$env{'form.fieldname'}." with result ".$put_result.'
'); + $r->print(&mt('Added new Metadata Field [_1] with result [_2]', + ''.$env{'form.fieldname'}.'',$put_result). + '
'); $r->print(&continue()); } else { my $fields = &get_deleted_meta_fieldnames($env{'request.course.id'}); if ($fields) { - $r->print('You may undelete previously deleted fields.
Check those you wish to undelete and click Undelete.
'); + $r->print(&mt('You may undelete previously deleted fields.'). + '
'. + &mt('Check those you wish to undelete and click Undelete.'). + '
'); $r->print(''); foreach my $key(keys(%$fields)) { - $r->print(''.$$fields{$key}.'
print('
print(''); + $r->print(''); $r->print('
'); } - $r->print('
Or you may enter a new metadata field name.
'); + $r->print('
'. + &mt('[_1]Or[_2] you may enter a new metadata field name.', + '',''). + ''); $r->print('
'); - $r->print(''); + $r->print(''); + $r->print('
'); } - $r->print(''); &endSettingsScreen($r); } @@ -5895,6 +6755,11 @@ sub setrestrictmeta { &startSettingsScreen($r,'parmset',$crstype); my $key_base = $env{'course.'.$env{'request.course.id'}.'.'}; my $save_field = ''; + my %lt = &Apache::lonlocal::texthash( + addm => 'Add Metadata Field', + ordm => 'Order Metadata Fields', + save => 'Save', + ); if ($env{'form.restrictmeta'}) { foreach my $field (sort(keys(%env))) { if ($field=~m/^form.(.+)_(.+)$/) { @@ -5933,28 +6798,25 @@ sub setrestrictmeta { my %metadata_fields = &Apache::lonmeta::fieldnames('portfolio'); # Now get possible added metadata fields my $added_metadata_fields = &get_added_meta_fieldnames($env{'request.course.id'}); - my $row_alt = 1; $output .= &Apache::loncommon::start_data_table(); foreach my $field (sort(keys(%metadata_fields))) { if ($field ne 'courserestricted') { - $row_alt = $row_alt ? 0 : 1; - $output.= &output_row($r, $field, $metadata_fields{$field}); + $output.= &output_row($r,$field,$metadata_fields{$field}); } } my $buttons = (< +
- +

- + ENDButtons my $added_flag = 1; foreach my $field (sort(keys(%$added_metadata_fields))) { - $row_alt = $row_alt ? 0 : 1; - $output.= &output_row($r, $field, $$added_metadata_fields{$field},$added_flag, $row_alt); # FIXME: wrong parameters + $output.= &output_row($r,$field,$$added_metadata_fields{$field},$added_flag); } $output .= &Apache::loncommon::end_data_table(); $r->print(<) { if ($configline !~ /\S/ || $configline=~/^\#/) { next; } chomp($configline); @@ -6381,6 +7239,12 @@ sub parm_change_log { } if ($last) { ($folder) = &Apache::lonnet::decode_symb($last); } } + my $numgroups = 0; + my @groups; + if ($env{'request.course.groups'} ne '') { + @groups = split(/:/,$env{'request.course.groups'}); + $numgroups = scalar(@groups); + } foreach my $id (sort { if ($parmlog{$b}{'exe_time'} ne $parmlog{$a}{'exe_time'}) { return $parmlog{$b}{'exe_time'} <=>$parmlog{$a}{'exe_time'} @@ -6418,9 +7282,10 @@ sub parm_change_log { my $typeflag = ($changed =~/\.type$/ && !exists($parmlog{$id}{'logentry'}{$changed.'.type'})); my ($realm,$section,$parmname,$part,$what,$middle,$uname,$udom,$issection,$realmdescription)= - &components($changed,$parmlog{$id}{'uname'},$parmlog{$id}{'udom'},undef,undef,$typeflag); + &components($changed,$parmlog{$id}{'uname'},$parmlog{$id}{'udom'},$typeflag); if ($env{'request.course.sec'} ne '') { - next if (($issection ne '') && ($issection ne $env{'request.course.sec'})); + next if (($issection ne '') && (!(($issection eq $env{'request.course.sec'}) || + ($numgroups && (grep(/^\Q$issection\E$/,@groups)))))); if ($uname ne '') { my $stusection = &Apache::lonnet::getsection($uname,$udom,$env{'request.course.id'}); next if (($stusection ne '-1') && ($stusection ne $env{'request.course.sec'})); @@ -6454,8 +7319,12 @@ sub parm_change_log { $parmitem = &mt($parmitem); $output .= &mt('Type: [_1]',$parmitem); } else { + my $toolsymb; + if ($middle =~ /ext\.tool$/) { + $toolsymb = $middle; + } my ($level,@all)=&parmval_by_symb($what,$middle, - &Apache::lonnet::metadata($middle,$what), + &Apache::lonnet::metadata($middle,$what,$toolsymb), $uname,$udom,$issection,$issection,$courseopt); my $showvalue = $value; if ($istype{$parmname} eq '') {