--- loncom/interface/lonparmset.pm 2020/02/12 16:25:47 1.596 +++ loncom/interface/lonparmset.pm 2020/10/29 23:24:13 1.597 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Handler to set parameters for assessments # -# $Id: lonparmset.pm,v 1.596 2020/02/12 16:25:47 raeburn Exp $ +# $Id: lonparmset.pm,v 1.597 2020/10/29 23:24:13 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -1241,12 +1241,16 @@ 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_(listing|scope)_/; - var deeplinkUrlsRegExp = /^deeplink_urls_/; - var deeplinkltiRegExp = /^deeplink_lti_/; - var deeplinkkeyRegExp = /^deeplink_key_/; + var deeplinkRegExp = /^deeplink_/; + var dlListScopeRegExp = /^deeplink_(listing|scope)_/; + var dlLinkUrlsRegExp = /^deeplink_urls_/; + var dlLtiRegExp = /^deeplink_lti_/; + 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) { @@ -1275,61 +1279,117 @@ function validateParms() { } } } - } else if (ipallowRegExp.test(name)) { - var identifier = name.replace(ipallowRegExp,''); - var possallow = document.parmform.elements[i].value; - possallow = possallow.replace(/^\s+|\s+$/g,''); - if (patternIP.test(possallow)) { - if (document.parmform.elements['set_'+identifier].value) { - possallow = ','+possallow; - } - document.parmform.elements['set_'+identifier].value += possallow; - } - } else if (ipdenyRegExp.test(name)) { - var identifier = name.replace(ipdenyRegExp,''); - var possdeny = document.parmform.elements[i].value; - possdeny = possdeny.replace(/^\s+|\s+$/g,''); - if (patternIP.test(possdeny)) { - possdeny = '!'+possdeny; - if (document.parmform.elements['set_'+identifier].value) { - possdeny = ','+possdeny; + } else if (ipRegExp.test(name)) { + if (ipallowRegExp.test(name)) { + var identifier = name.replace(ipallowRegExp,''); + var possallow = document.parmform.elements[i].value; + possallow = possallow.replace(/^\s+|\s+$/g,''); + if (patternIP.test(possallow)) { + if (document.parmform.elements['set_'+identifier].value) { + possallow = ','+possallow; + } + document.parmform.elements['set_'+identifier].value += possallow; + } + } else if (ipdenyRegExp.test(name)) { + var identifier = name.replace(ipdenyRegExp,''); + var possdeny = document.parmform.elements[i].value; + possdeny = possdeny.replace(/^\s+|\s+$/g,''); + if (patternIP.test(possdeny)) { + possdeny = '!'+possdeny; + if (document.parmform.elements['set_'+identifier].value) { + possdeny = ','+possdeny; + } + document.parmform.elements['set_'+identifier].value += possdeny; } - document.parmform.elements['set_'+identifier].value += possdeny; } } else if (deeplinkRegExp.test(name)) { - var identifier = name.replace(deeplinkRegExp,''); - var possdeeplink = document.parmform.elements[i].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 (deeplinkUrlsRegExp.test(name)) { - if (document.parmform.elements[i].checked) { - var identifier = name.replace(deeplinkUrlsRegExp,''); - 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 (deeplinkltiRegExp.test(name)) { - var identifier = name.replace(deeplinkltiRegExp,''); - var posslti = document.parmform.elements[i].value; - posslti = posslti.replace(/\D+/g,''); - if (document.parmform.elements['set_'+identifier].value) { - posslti = ':'+posslti; - } - document.parmform.elements['set_'+identifier].value += posslti; - } else if (deeplinkkeyRegExp.test(name)) { - var identifier = name.replace(deeplinkkeyRegExp,''); - var posskey = document.parmform.elements[i].value; - posskey = posskey.replace(/\W+/g,''); - if (document.parmform.elements['set_'+identifier].value) { - posslti = ':'+posskey; + if (dlListScopeRegExp.test(name)) { + var identifier = name.replace(dlListScopeRegExp,''); + var idx = document.parmform.elements[i].selectedIndex; + if (idx > 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 (dlLinkUrlsRegExp.test(name)) { + if (document.parmform.elements[i].checked) { + var identifier = name.replace(dlLinkUrlsRegExp,''); + 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 (dlLtiRegExp.test(name)) { + var identifier = name.replace(dlLtiRegExp,''); + if (isRadioSet('deeplink_urls_'+identifier,'lti')) { + var posslti = document.parmform.elements[i].value; + posslti = posslti.replace(/\D+/g,''); + if (posslti.length) { + if (document.parmform.elements['set_'+identifier].value) { + posslti = ':'+posslti; + } + document.parmform.elements['set_'+identifier].value += posslti; + } else { + document.parmform.elements['set_'+identifier].value = ''; + alert("A link type of 'deep with LTI launch' was selected but no 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_urls_'+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) { + posskey = ':'+posskey; + } + 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; + } } - document.parmform.elements['set_'+identifier].value += posskey; } } } @@ -1337,6 +1397,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 $b } keys(%posslti)) { - $extra .= $lti.':'.&js_escape($posslti{$lti}).','; + $extra .= $lti.':'.&escape($posslti{$lti}).','; } $extra =~ s/,$//; } + 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) { @@ -1766,7 +1870,7 @@ sub print_row { # @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 {strring} $extra - extra informatio to pass to plink. +# @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,$extra)=@_; @@ -2517,7 +2621,7 @@ function group_or_section(caller) { } if (%grouphash) { - $groups=&mt('Group:').' '; - foreach my $item ('listing','scope','urls') { + foreach my $item (@components) { $output .= ''; } $output .= ''; foreach my $item (@components) { $output .= '
'.$titles{$item}.'
'; - if ($item eq 'urls') { + if (($item eq 'urls') || ($item eq 'menus')) { my $selected = $values{$item}; foreach my $option (@{$options{$item}}) { - if ($option eq 'lti') { + if (($item eq 'urls') && ($option eq 'lti')) { next unless (keys(%posslti)); + } elsif (($item eq 'menus') && ($option eq 'colls')) { + next unless (@possmenus); } my $checked; - if ($selected =~ /^\Q$option\E/) { + 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; @@ -4944,7 +5080,7 @@ sub string_deeplink_selector { $output .= ''; - if ($option eq 'key') { + if (($item eq 'urls') && ($option eq 'key')) { my $visibility="hidden"; my $currkey; if ($checked) { @@ -4952,26 +5088,42 @@ sub string_deeplink_selector { $currkey = (split(/\:/,$values{$item}))[1]; } $output .= ' '. - ''; - } elsif ($option eq 'lti') { + ''; + } elsif (($option eq 'lti') || ($option eq 'colls')) { my $display="none"; - my ($currlti,$blankcheck); + my ($current,$blankcheck,@possibles); if ($checked) { $display = 'inline-block'; - $currlti = (split(/\:/,$values{$item}))[1]; + if ($option eq 'lti') { + $current = (split(/\:/,$selected))[1]; + } else { + $current = $selected; + } } else { $blankcheck = ' selected="selected"'; } + if ($option eq 'lti') { + @possibles = keys(%posslti); + } else { + @possibles = @possmenus; + } $output .= '
 
'; } @@ -5035,7 +5187,7 @@ my %strings = => [['_allowfrom_','Hostname(s), or IP(s) from which access is allowed'], ['_denyfrom_','Hostname(s) or IP(s) from which access is disallowed']], 'string_deeplink' - => [['on','Set choices for link protection, resource listing, and access scope']], + => [['on','Set choices for link protection, resource listing, access scope, and shown menu items']], ); @@ -5046,7 +5198,7 @@ my %stringmatches = ( => [['_allowfrom_','[^\!]+'], ['_denyfrom_','\!']], 'string_deeplink' - => [['on','^(full|absent|grades|details|datestatus)\,(res|map|rec)\,(any|only|key\:\w+|lti\:\d+)$']], + => [['on','^(full|absent|grades|details|datestatus)\,(res|map|rec)\,(any|only|key\:\w+|lti\:\d+)\,(\d+|)$']], ); my %stringtypes = (