--- loncom/interface/courseprefs.pm 2021/08/04 19:59:10 1.93 +++ loncom/interface/courseprefs.pm 2022/10/19 00:03:10 1.117 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Handler to set configuration settings for a course # -# $Id: courseprefs.pm,v 1.93 2021/08/04 19:59:10 raeburn Exp $ +# $Id: courseprefs.pm,v 1.117 2022/10/19 00:03:10 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -52,12 +52,16 @@ This module is used for configuration of =item process_changes() +=item process_linkprot() + =item get_sec_str() =item check_clone() =item store_changes() +=item store_linkprot() + =item update_env() =item display_disallowed() @@ -112,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() @@ -220,6 +224,7 @@ use Apache::lonparmset; use Apache::courseclassifier; use Apache::lonlocal; use LONCAPA qw(:DEFAULT :match); +use Crypt::CBC; my $registered_cleanup; my $modified_courses; @@ -288,7 +293,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', @@ -317,7 +322,7 @@ sub handler { 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', @@ -365,14 +370,28 @@ sub handler { } my %values=&Apache::lonnet::dump('environment',$cdom,$cnum); - my %courselti=&Apache::lonnet::dump('lti',$cdom,$cnum,undef,undef,undef,1); - if ($courselti{'lock'}) { - delete($courselti{'lock'}); + 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); + foreach my $id (keys(%linkprot)) { + if (ref($linkprot{$id}) eq 'HASH') { + if (ref($ltienc{$id}) eq 'HASH') { + $values{'linkprot'}{$id} = { %{$linkprot{$id}}, %{$ltienc{$id}} }; + } else { + $values{'linkprot'}{$id} = $linkprot{$id}; + } + } + unless ($phase eq 'process') { + if (ref($values{'linkprot'}{$id}) eq 'HASH') { + delete($values{'linkprot'}{$id}{'secret'}); + } + } + } + if ($linkprot{'lock'}) { + delete($linkprot{'lock'}); } - $values{'linkprotection'} = \%courselti; my @prefs_order = ('courseinfo','localization','feedback','discussion', 'classlists','appearance','grading','printouts', - 'menuitems','linkprotection','spreadsheet','bridgetasks', + 'menuitems','linkprot','spreadsheet','bridgetasks', 'lti','other'); my %prefs = ( @@ -473,7 +492,8 @@ sub handler { help => 'Course_Prefs_Display', ordered => ['default_xml_style','pageseparators', 'disable_receipt_display','texengine', - 'tthoptions','uselcmath','usejsme'], + 'tthoptions','uselcmath','usejsme', + 'inline_chem','extresource'], itemtext => { default_xml_style => 'Default XML style file', pageseparators => 'Visibly Separate Items on Pages', @@ -482,6 +502,8 @@ sub handler { tthoptions => 'Default set of options to pass to tth/m when converting TeX', 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' => @@ -563,7 +585,7 @@ sub handler { menucollections => 'Menu collections', }, }, - 'linkprotection' => + 'linkprot' => { text => 'Link protection', help => 'Course_Prefs_Linkprotection', @@ -581,10 +603,14 @@ sub handler { ); if (($phase eq 'process') && ($parm_permission->{'process'})) { my @allitems = &get_allitems(%prefs); - &Apache::lonconfigsettings::make_changes($r,$cdom,$phase,$context, - \@prefs_order,\%prefs,\%values, - $cnum,undef,\@allitems, - 'coursepref',$parm_permission); + my $result = &Apache::lonconfigsettings::make_changes($r,$cdom,$phase,$context, + \@prefs_order,\%prefs,\%values, + $cnum,undef,\@allitems, + 'coursepref',$parm_permission); + if ((ref($result) eq 'HASH') && (keys(%{$result}))) { + $r->rflush(); + &devalidate_remote_courseprefs($cdom,$cnum,$result); + } } elsif (($phase eq 'display') && ($parm_permission->{'display'})) { my $noedit; if (ref($parm_permission) eq 'HASH') { @@ -595,7 +621,7 @@ sub handler { my $jscript = &get_jscript($cid,$cdom,$phase,$crstype,\%values,$noedit); my @allitems = &get_allitems(%prefs); &Apache::lonconfigsettings::display_settings($r,$cdom,$phase,$context, - \@prefs_order,\%prefs,\%values,undef,$jscript,\@allitems,$crstype, + \@prefs_order,\%prefs,\%values,$cnum,$jscript,\@allitems,$crstype, 'coursepref',$parm_permission); } else { &Apache::lonconfigsettings::display_choices($r,$phase,$context, @@ -648,7 +674,7 @@ sub get_allitems { } sub print_config_box { - my ($r,$cdom,$phase,$action,$item,$settings,$allitems,$crstype,$parm_permission) = @_; + my ($r,$cdom,$cnum,$phase,$action,$item,$settings,$allitems,$crstype,$parm_permission) = @_; my $ordered = $item->{'ordered'}; my $itemtext = $item->{'itemtext'}; my $noedit; @@ -778,8 +804,8 @@ sub print_config_box { $output .= &print_lti($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype,$noedit); } elsif ($action eq 'menuitems') { $output .= &print_menuitems('bottom',$cdom,$settings,$itemtext,\$rowtotal,$crstype,$noedit); - } elsif ($action eq 'linkprotection') { - $output .= &print_linkprotection($cdom,$settings,\$rowtotal,$crstype,$noedit); + } elsif ($action eq 'linkprot') { + $output .= &print_linkprotection($cdom,$cnum,$settings,\$rowtotal,$crstype,$noedit,'course'); } elsif ($action eq 'other') { $output .= &print_other($cdom,$settings,$allitems,\$rowtotal,$crstype,$noedit); } @@ -792,8 +818,8 @@ sub print_config_box { } sub process_changes { - my ($cdom,$cnum,$action,$values,$item,$changes,$allitems,$disallowed,$crstype) = @_; - my (%newvalues,%courselti,$errors); + my ($cdom,$cnum,$action,$values,$item,$changes,$allitems,$disallowed,$crstype,$lastactref) = @_; + my (%newvalues,$errors); if (ref($item) eq 'HASH') { if (ref($changes) eq 'HASH') { my @ordered; @@ -810,14 +836,11 @@ sub process_changes { } } } - } elsif ($action eq 'linkprotection') { - if (ref($values->{'linkprotection'}) eq 'HASH') { - foreach my $id (keys(%{$values->{'linkprotection'}})) { + } elsif ($action eq 'linkprot') { + if (ref($values->{$action}) eq 'HASH') { + foreach my $id (keys(%{$values->{$action}})) { if ($id =~ /^\d+$/) { push(@ordered,$id); - unless (ref($values->{'linkprotection'}->{$id}) eq 'HASH') { - $courselti{$id} = ''; - } } } } @@ -962,77 +985,9 @@ sub process_changes { } elsif ($values->{'menucollections'}) { $changes->{'menucollections'} = ''; } - } elsif ($action eq 'linkprotection') { - my %menutitles = <imenu_titles(); - my (@items,%deletions,%itemids,%haschanges); - if ($env{'form.linkprot_add'}) { - my $name = $env{'form.linkprot_name_add'}; - $name =~ s/(`)/'/g; - my ($newid,$error) = &get_courselti_id($cdom,$cnum,$name); - if ($newid) { - $itemids{'add'} = $newid; - push(@items,'add'); - $haschanges{$newid} = 1; - } else { - $errors .= '<span class="LC_error">'. - &mt('Failed to acquire unique ID for link protection'). - '</span>'; - } - } - if (ref($values->{'linkprotection'}) eq 'HASH') { - my @todelete = &Apache::loncommon::get_env_multiple('form.linkprot_del'); - my $maxnum = $env{'form.linkprot_maxnum'}; - for (my $i=0; $i<=$maxnum; $i++) { - my $itemid = $env{'form.linkprot_id_'.$i}; - $itemid =~ s/\D+//g; - if ($itemid) { - if (ref($values->{'linkprotection'}->{$itemid}) eq 'HASH') { - push(@items,$i); - $itemids{$i} = $itemid; - if ((@todelete > 0) && (grep(/^$i$/,@todelete))) { - $deletions{$itemid} = $values->{'linkprotection'}->{$itemid}->{'name'}; - } - } - } - } - - } - foreach my $idx (@items) { - my $itemid = $itemids{$idx}; - next unless ($itemid); - if (exists($deletions{$itemid})) { - $courselti{$itemid} = $deletions{$itemid}; - $haschanges{$itemid} = 1; - next; - } - my %current; - if (ref($values->{'linkprotection'}) eq 'HASH') { - if (ref($values->{'linkprotection'}->{$itemid}) eq 'HASH') { - foreach my $key (keys(%{$values->{'linkprotection'}->{$itemid}})) { - $current{$key} = $values->{'linkprotection'}->{$itemid}->{$key}; - } - } - } - foreach my $inner ('name','key','secret','lifetime','version') { - my $formitem = 'form.linkprot_'.$inner.'_'.$idx; - $env{$formitem} =~ s/(`)/'/g; - if ($inner eq 'lifetime') { - $env{$formitem} =~ s/[^\d.]//g; - } - unless ($idx eq 'add') { - if ($current{$inner} ne $env{$formitem}) { - $haschanges{$itemid} = 1; - } - } - if ($env{$formitem} ne '') { - $courselti{$itemid}{$inner} = $env{$formitem}; - } - } - } - if (keys(%haschanges)) { - foreach my $entry (keys(%haschanges)) { - $changes->{$entry} = $courselti{$entry}; - } + } elsif ($action eq 'linkprot') { + if (ref($values) eq 'HASH') { + $errors = &process_linkprot($cdom,$cnum,$values->{$action},$changes,'course',$lastactref); } } else { foreach my $entry (@ordered) { @@ -1163,7 +1118,9 @@ sub process_changes { $autocoowner = $domconf{'autoenroll'}{'co-owners'}; } } - unless ($autocoowner) { + if ($autocoowner) { + $newvalues{'co-owners'} = $values->{'internal.co-owners'}; + } else { my @keepcoowners = &Apache::loncommon::get_env_multiple('form.coowners'); my @pendingcoowners = &Apache::loncommon::get_env_multiple('form.pendingcoowners'); my @invitecoowners = &Apache::loncommon::get_env_multiple('form.invitecoowners'); @@ -1208,6 +1165,8 @@ sub process_changes { if ($pendingcoowners ne '') { @newpending = @pendingcoown; } + } else { + @newcoown = @currcoown; } $newvalues{'pendingco-owners'} = join(',',sort(@newpending)); $newvalues{'co-owners'} = join(',',sort(@newcoown)); @@ -1507,10 +1466,54 @@ 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} = ''; + } } 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}; } @@ -1523,23 +1526,257 @@ sub process_changes { return $errors; } -sub get_courselti_id { - my ($cdom,$cnum,$name) = @_; - # get lock on lti db in course +sub process_linkprot { + my ($cdom,$cnum,$values,$changes,$context,$lastactref) = @_; + my ($home,$dest,$ltiauth,$privkey,$privnum,$cipher,$errors,%linkprot); + if (ref($values) eq 'HASH') { + foreach my $id (keys(%{$values})) { + if ($id =~ /^\d+$/) { + unless (ref($values->{$id}) eq 'HASH') { + $linkprot{$id} = ''; + } + } + } + } + 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'}); + } + } + } + } + } + } + if ($context eq 'domain') { + $dest = '/adm/domainprefs'; + $ltiauth = 1; + } else { + $dest = '/adm/courseprefs'; + if (exists($env{'course.'.$env{'request.course.id'}.'.internal.ltiauth'})) { + $ltiauth = $env{'course.'.$env{'request.course.id'}.'.internal.ltiauth'}; + } else { + my %domdefs = &Apache::lonnet::get_domain_defaults($cdom); + $ltiauth = $domdefs{'crsltiauth'}; + } + } + my $switchserver = &check_switchserver($cdom,$cnum,$context,$dest); + my (@items,%deletions,%itemids,%haschanges); + if ($env{'form.linkprot_add'}) { + my $name = $env{'form.linkprot_name_add'}; + $name =~ s/(`)/'/g; + my ($newid,$error) = &get_linkprot_id($cdom,$cnum,$name,$context); + if ($newid) { + $itemids{'add'} = $newid; + push(@items,'add'); + $haschanges{$newid} = 1; + } else { + $errors .= '<span class="LC_error">'. + &mt('Failed to acquire unique ID for link protection'). + '</span>'; + } + } + if (ref($values) eq 'HASH') { + my @todelete = &Apache::loncommon::get_env_multiple('form.linkprot_del'); + my $maxnum = $env{'form.linkprot_maxnum'}; + for (my $i=0; $i<$maxnum; $i++) { + my $itemid = $env{'form.linkprot_id_'.$i}; + $itemid =~ s/\D+//g; + if ($itemid) { + if (ref($values->{$itemid}) eq 'HASH') { + push(@items,$i); + $itemids{$i} = $itemid; + if ((@todelete > 0) && (grep(/^$i$/,@todelete))) { + $deletions{$itemid} = $values->{$itemid}->{'name'}; + } + } + } + } + } + foreach my $idx (@items) { + my $itemid = $itemids{$idx}; + next unless ($itemid); + if (exists($deletions{$itemid})) { + $linkprot{$itemid} = $deletions{$itemid}; + $haschanges{$itemid} = 1; + next; + } + my %current; + if (ref($values) eq 'HASH') { + if (ref($values->{$itemid}) eq 'HASH') { + foreach my $key (keys(%{$values->{$itemid}})) { + $current{$key} = $values->{$itemid}->{$key}; + } + } + } + foreach my $inner ('name','lifetime','version') { + my $formitem = 'form.linkprot_'.$inner.'_'.$idx; + $env{$formitem} =~ s/(`)/'/g; + if ($inner eq 'lifetime') { + $env{$formitem} =~ s/[^\d.]//g; + } + unless ($idx eq 'add') { + if ($current{$inner} ne $env{$formitem}) { + $haschanges{$itemid} = 1; + } + } + if ($env{$formitem} ne '') { + $linkprot{$itemid}{$inner} = $env{$formitem}; + } + } + my $urlitem = 'form.linkprot_returnurl_'.$idx; + my $urlparamname = 'form.linkprot_urlparam_'.$idx; + if ($env{$urlitem} == 1) { + $env{$urlparamname} =~ s/(`)/'/g; + } elsif (exists($env{$urlparamname})) { + $env{$urlparamname} = ''; + } + unless ($idx eq 'add') { + if ((!$current{'returnurl'} && ($env{$urlparamname} ne '')) || + ($current{'returnurl'} && ($env{$urlparamname} eq ''))) { + $haschanges{$itemid} = 1; + } + } + if ($env{$urlparamname} ne '') { + $linkprot{$itemid}{'returnurl'} = $env{$urlparamname}; + } + if ($ltiauth) { + my $reqitem = 'form.linkprot_requser_'.$idx; + $env{$reqitem} =~ s/(`)/'/g; + unless ($idx eq 'add') { + if ((!$current{'requser'} && $env{$reqitem}) || + ($current{'requser'} && !$env{$reqitem})) { + $haschanges{$itemid} = 1; + } + } + if ($env{$reqitem} == 1) { + $linkprot{$itemid}{'requser'} = $env{$reqitem}; + foreach my $inner ('mapuser','notstudent') { + my $formitem = 'form.linkprot_'.$inner.'_'.$idx; + $env{$formitem} =~ s/(`)/'/g; + if ($inner eq 'mapuser') { + if ($env{$formitem} eq 'other') { + my $mapuser = $env{'form.linkprot_customuser_'.$idx}; + $mapuser =~ s/(`)/'/g; + $mapuser =~ s/^\s+|\s+$//g; + if ($mapuser ne '') { + $linkprot{$itemid}{$inner} = $mapuser; + } else { + delete($linkprot{$itemid}{'requser'}); + last; + } + } elsif ($env{$formitem} eq 'sourcedid') { + $linkprot{$itemid}{$inner} = 'lis_person_sourcedid'; + } elsif ($env{$formitem} eq 'email') { + $linkprot{$itemid}{$inner} = 'lis_person_contact_email_primary'; + } + } else { + $linkprot{$itemid}{$inner} = $env{$formitem}; + } + unless ($idx eq 'add') { + if ($current{$inner} ne $linkprot{$itemid}{$inner}) { + $haschanges{$itemid} = 1; + } + } + } + } + } + unless ($switchserver) { + my $keyitem = 'form.linkprot_key_'.$idx; + $env{$keyitem} =~ s/(`)/'/g; + unless ($idx eq 'add') { + if ($current{'key'} ne $env{$keyitem}) { + $haschanges{$itemid} = 1; + } + } + if ($env{$keyitem} ne '') { + $linkprot{$itemid}{'key'} = $env{$keyitem}; + } + my $secretitem = 'form.linkprot_secret_'.$idx; + $env{$secretitem} =~ s/(`)/'/g; + if ($current{'usable'}) { + if ($env{'form.linkprot_changesecret_'.$idx}) { + if ($env{$secretitem} ne '') { + if ($privnum && $cipher) { + $linkprot{$itemid}{'secret'} = $cipher->encrypt_hex($env{$secretitem}); + $linkprot{$itemid}{'cipher'} = $privnum; + } else { + $linkprot{$itemid}{'secret'} = $env{$secretitem}; + } + $haschanges{$itemid} = 1; + } + } else { + $linkprot{$itemid}{'secret'} = $current{'secret'}; + $linkprot{$itemid}{'cipher'} = $current{'cipher'}; + } + } elsif ($env{$secretitem} ne '') { + if ($privnum && $cipher) { + $linkprot{$itemid}{'secret'} = $cipher->encrypt_hex($env{$secretitem}); + $linkprot{$itemid}{'cipher'} = $privnum; + } else { + $linkprot{$itemid}{'secret'} = $env{$secretitem}; + } + $haschanges{$itemid} = 1; + } + } + } + if (keys(%haschanges)) { + foreach my $entry (keys(%haschanges)) { + $changes->{$entry} = $linkprot{$entry}; + } + if (ref($lastactref) eq 'HASH') { + $lastactref->{'courselti'} = 1; + } + } + return $errors; +} + +sub get_linkprot_id { + my ($cdom,$cnum,$name,$context) = @_; + # get lock on lti db in course or linkprot db in domain my $lockhash = { lock => $env{'user.name'}. ':'.$env{'user.domain'}, }; my $tries = 0; - my $gotlock = &Apache::lonnet::newput('lti',$lockhash,$cdom,$cnum); + my $gotlock; + if ($context eq 'domain') { + $gotlock = &Apache::lonnet::newput_dom('linkprot',$lockhash,$cdom); + } else { + $gotlock = &Apache::lonnet::newput('lti',$lockhash,$cdom,$cnum); + } my ($id,$error); while (($gotlock ne 'ok') && ($tries<10)) { $tries ++; sleep (0.1); - $gotlock = &Apache::lonnet::newput('lti',$lockhash,$cdom,$cnum); + if ($context eq 'domain') { + $gotlock = &Apache::lonnet::newput_dom('linkprot',$lockhash,$cdom); + } else { + $gotlock = &Apache::lonnet::newput('lti',$lockhash,$cdom,$cnum); + } } if ($gotlock eq 'ok') { - my %currids = &Apache::lonnet::dump('lti',$cdom,$cnum,undef,undef,undef,1); + my %currids; + if ($context eq 'domain') { + %currids = &Apache::lonnet::dump_dom('linkprot',$cdom); + } else { + %currids = &Apache::lonnet::dump('lti',$cdom,$cnum,undef,undef,undef,1); + } if ($currids{'lock'}) { delete($currids{'lock'}); if (keys(%currids)) { @@ -1553,14 +1790,25 @@ sub get_courselti_id { $id = 1; } if ($id) { - unless (&Apache::lonnet::newput('lti',{ $id => $name },$cdom,$cnum) eq 'ok') { - $error = 'nostore'; + if ($context eq 'domain') { + unless (&Apache::lonnet::newput_dom('linkprot',{ $id => $name },$cdom) eq 'ok') { + $error = 'nostore'; + } + } else { + unless (&Apache::lonnet::newput('lti',{ $id => $name },$cdom,$cnum) eq 'ok') { + $error = 'nostore'; + } } } else { $error = 'nonumber'; } } - my $dellockoutcome = &Apache::lonnet::del('lti',['lock'],$cdom,$cnum); + my $dellockoutcome; + if ($context eq 'domain') { + $dellockoutcome = &Apache::lonnet::del_dom('linkprot',['lock'],$cdom); + } else { + $dellockoutcome = &Apache::lonnet::del('lti',['lock'],$cdom,$cnum); + } } else { $error = 'nolock'; } @@ -1611,10 +1859,10 @@ sub store_changes { my ($chome,$output); my (%storehash,@delkeys,@need_env_update,@oldcloner,%oldlinkprot); if ((ref($values) eq 'HASH') && (ref($changes) eq 'HASH')) { - if (ref($values->{'linkprotection'}) eq 'HASH') { - %oldlinkprot = %{$values->{'linkprotection'}}; + if (ref($values->{'linkprot'}) eq 'HASH') { + %oldlinkprot = %{$values->{'linkprot'}}; } - delete($values->{'linkprotection'}); + delete($values->{'linkprot'}); %storehash = %{$values}; } else { if ($crstype eq 'Community') { @@ -1627,7 +1875,7 @@ sub store_changes { my ($numchanges,$skipstore); if (ref($changes) eq 'HASH') { $numchanges = scalar(keys(%{$changes})); - if (($numchanges == 1) && (exists($changes->{'linkprotection'}))) { + if (($numchanges == 1) && (exists($changes->{'linkprot'}))) { $skipstore = 1; } elsif (!$numchanges) { if ($crstype eq 'Community') { @@ -1650,7 +1898,7 @@ sub store_changes { if (grep(/^\Q$item\E$/,@{$actions})) { $output .= '<h3>'.&mt($prefs->{$item}{'text'}).'</h3>'; if (ref($changes->{$item}) eq 'HASH') { - if ((keys(%{$changes->{$item}}) > 0) || ($item eq 'linkprotection')) { + if (keys(%{$changes->{$item}}) > 0) { $output .= &mt('Changes made:').'<ul style="list-style:none;">'; if ($item eq 'other') { foreach my $key (sort(keys(%{$changes->{$item}}))) { @@ -1663,41 +1911,8 @@ sub store_changes { "'$storehash{$key}'")).'</li>'; } } - } elsif ($item eq 'linkprotection') { - if (&Apache::lonnet::put('lti',$changes->{'linkprotection'},$cdom,$cnum,1) eq 'ok') { - my $hashid=$cdom.'_'.$cnum; - &Apache::lonnet::devalidate_cache_new('courselti',$hashid); - foreach my $itemid (sort { $a <=> $b } %{$changes->{'linkprotection'}}) { - if (ref($changes->{'linkprotection'}->{$itemid}) eq 'HASH') { - my %values = %{$changes->{'linkprotection'}->{$itemid}}; - my %desc = &linkprot_names(); - my $display; - foreach my $title ('name','lifetime','version','key','secret') { - if ($title eq 'secret') { - my $length = length($values{$title}); - $display .= $desc{$title}.': '.('*' x $length); - } elsif ($title eq 'version') { - if ($values{$title} eq 'LTI-1p0') { - $display .= $desc{$title}.': 1.1, '; - } - } else { - $display .= $desc{$title}.': '.$values{$title}.', '; - } - } - $output .= '<li>'.&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]','<i>'.$itemid.'</i>', - "'$display'")).'</li>'; - } elsif (ref($oldlinkprot{$itemid}) eq 'HASH') { - my $oldname = $oldlinkprot{$itemid}{'name'}; - $output .= '<li>'.&Apache::lonhtmlcommon::confirm_success(&mt('Deleted setting for [_1]','<i>'."$itemid ($oldname)".'</i>')).'</li>'; - } - } - } else { - $output .= '<li>'. - '<span class="LC_error">'. - &mt('An error occurred when saving changes to link protection settings, which remain unchanged.'). - '</span>'. - '</li>'; - } + } elsif ($item eq 'linkprot') { + $output .= &store_linkprot($cdom,$cnum,'course',$changes->{$item},\%oldlinkprot); } else { if (ref($prefs->{$item}->{'ordered'}) eq 'ARRAY') { my @settings = @{$prefs->{$item}->{'ordered'}}; @@ -1729,12 +1944,52 @@ sub store_changes { if ($msg ne '') { $output .= '<li>'.&Apache::lonhtmlcommon::confirm_success(&mt($displayname)).'<ul class="LC_success">'.$msg.'</ul></li>'; } + } 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 = '<b>'.$changes->{$item}{$key}.'</b>'; + } else { + push(@delkeys,$key); + if (exists($values->{'tzover'})) { + push(@delkeys,'tzover'); + } + $output .= '<li>'.&Apache::lonhtmlcommon::confirm_success(&mt('Deleted setting for [_1]', + '<i>'.$displayname.'</i>')).'</li>'; + } + } + 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 .= '<li>'.&Apache::lonhtmlcommon::confirm_success($tzovertext).'</li>'; + } else { + $displayval .= '<br />'.(' 'x5).$tzovertext; + } + } + if ($displayval ne '') { + $output .= '<li>'.&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]', + '<i>'.$displayname.'</i>',$displayval)).'</li>'; + } + } } 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 'feedback') { @@ -1852,12 +2107,44 @@ sub store_changes { $displayval = &Apache::lonlocal::locallocaltime($displayval); } elsif ($key eq 'categories') { $displayval = $env{'form.categories_display'}; - } elsif (($key eq 'canuse_pdfforms') || ($key eq 'usejsme') || ($key eq 'uselcmath')) { + } elsif (($key eq 'canuse_pdfforms') || ($key eq 'usejsme') || + ($key eq 'uselcmath') || ($key eq 'inline_chem')) { if ($changes->{$item}{$key} eq '1') { $displayval = &mt('Yes'); } 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', + "'<b>","</b>'",'<br />'); + } else { + $displayval = &mt('[_1]In tab[_2],[_3] with new tab for each external resource in course', + "'<b>","</b>'",'<br />'); + } + } 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', + "'<b>","</b>'",'<br />'); + } else { + $displayval = &mt('[_1]In pop-up window[_2],[_3] with new window for each external resource in course', + "'<b>","</b>'",'<br />'); + } + if (($width ne '') || ($height ne '')) { + if ($width ne '') { + $displayval .= '<br />'.&mt('Window width: [_1]px',$width); + } + if ($height ne '') { + $displayval .= '<br />'.&mt('Window height: [_1]px',$height); + } + } + } + } } if ($key eq 'co-owners') { if (ref($changes->{$item}{$key}) eq 'HASH') { @@ -1929,9 +2216,11 @@ sub store_changes { $output .= '<li>'.&Apache::lonhtmlcommon::confirm_success(&mt('Numbered menu collections:')).'<br />'. $displayval.'</li>'; } else { + unless (($key eq 'extresource') && ($changes->{$item}{$key} ne 'iframe')) { + $displayval = "'<b>$displayval</b>'"; + } $output .= '<li>'.&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]', - '<i>'.$displayname.'</i>', - "'<b>$displayval</b>'")); + '<i>'.$displayname.'</i>',$displayval)); if ($key eq 'url') { my $bkuptime=time; $output .= (' 'x2).&mt('(Previous URL backed up)').': '. @@ -2030,6 +2319,164 @@ sub store_changes { return $output; } +sub store_linkprot { + my ($cdom,$cnum,$context,$changes,$oldlinkprot) = @_; + my ($ltiauth,$home,$lti_save_error,$output,$error,%ltienc,@deletions); + if ($context eq 'domain') { + $ltiauth = 1; + $home = &Apache::lonnet::domain($cdom,'primary'); + } else { + $home = &Apache::lonnet::homeserver($cnum,$cdom); + if (exists($env{'course.'.$env{'request.course.id'}.'.internal.ltiauth'})) { + $ltiauth = $env{'course.'.$env{'request.course.id'}.'.internal.ltiauth'}; + } else { + my %domdefs = &Apache::lonnet::get_domain_defaults($cdom); + $ltiauth = $domdefs{'crsltiauth'}; + } + } + if (ref($changes) eq 'HASH') { + foreach my $id (sort { $a <=> $b } keys(%{$changes})) { + if (ref($changes->{$id}) eq 'HASH') { + if (exists($changes->{$id}->{'key'})) { + $ltienc{$id}{'key'} = $changes->{$id}->{'key'}; + delete($changes->{$id}->{'key'}); + } + if (exists($changes->{$id}->{'secret'})) { + $ltienc{$id}{'secret'} = $changes->{$id}->{'secret'}; + delete($changes->{$id}->{'secret'}); + } elsif (ref($oldlinkprot->{$id}) eq 'HASH') { + if (exists($oldlinkprot->{$id}{'usable'})) { + $changes->{$id}->{'usable'} = 1; + } + if (exists($oldlinkprot->{$id}{'cipher'})) { + $changes->{$id}->{'cipher'} = $oldlinkprot->{$id}{'cipher'}; + } + } + } + } + } + my @ids=&Apache::lonnet::current_machine_ids(); + if (keys(%ltienc) > 0) { + if ($context eq 'domain') { + foreach my $id (keys(%ltienc)) { + if (exists($ltienc{$id}{'secret'})) { + $changes->{$id}->{'usable'} = 1; + } + } + } else { + unless (($home eq 'no_host') || ($home eq '')) { + my $allowed; + foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } } + if ($allowed) { + if (&Apache::lonnet::put('nohist_ltienc',\%ltienc,$cdom,$cnum,1) eq 'ok') { + foreach my $id (keys(%ltienc)) { + if (exists($ltienc{$id}{'secret'})) { + $changes->{$id}->{'usable'} = 1; + } + } + } else { + $lti_save_error = 1; + } + } + } + } + } + unless ($lti_save_error) { + if ($context eq 'course') { + if (&Apache::lonnet::put('lti',$changes,$cdom,$cnum,1) eq 'ok') { + my $hashid=$cdom.'_'.$cnum; + &Apache::lonnet::devalidate_cache_new('courselti',$hashid); + unless (($home eq 'no_host') || ($home eq '')) { + if (grep(/^\Q$home\E$/,@ids)) { + &Apache::lonnet::devalidate_cache_new('courseltienc',$hashid); + } + } + } else { + $lti_save_error = 1; + } + } + unless ($lti_save_error) { + foreach my $id (sort { $a <=> $b } %{$changes}) { + if (ref($changes->{$id}) eq 'HASH') { + my %values = %{$changes->{$id}}; + my %desc = &linkprot_names(); + my $display; + foreach my $title ('name','lifetime','version','key','secret','returnurl') { + if (($title eq 'key') || ($title eq 'secret')) { + if (ref($ltienc{$id}) eq 'HASH') { + if (exists($ltienc{$id}{$title})) { + if ($title eq 'secret') { + my $length = length($ltienc{$id}{$title}); + $display .= $desc{$title}.': ['.&mt('not shown').'], '; + } else { + $display .= $desc{$title}.': '.$ltienc{$id}{$title}.', '; + } + } + } + } elsif ($title eq 'version') { + if ($values{$title} eq 'LTI-1p0') { + $display .= $desc{$title}.': 1.1, '; + } + } elsif ($title eq 'returnurl') { + if ($values{$title}) { + $display .= &mt('Return URL parameter').': '.$values{$title}.', '; + } + } else { + $display .= $desc{$title}.': '.$values{$title}.', '; + } + } + if ($ltiauth) { + if (($values{'requser'}) && ($values{'mapuser'} ne '')) { + if ($values{'mapuser'} eq 'lis_person_contact_email_primary') { + $display .= &mt('Source of username: Email address [_1]', + '(lis_person_contact_email_primary)').', '; + } elsif ($values{'mapuser'} eq 'lis_person_sourcedid') { + $display .= &mt('Source of username: User ID [_1]', + '(lis_person_sourcedid)').', '; + } else { + $display .= &mt('Source of username: [_1]',$values{'mapuser'}).', '; + } + if ($values{'notstudent'} eq 'auth') { + $display .= &mt('Display LON-CAPA login page if no match').', '; + } elsif ($values{'notstudent'} eq 'reject') { + $display .= &mt('Discontinue launch if no match').', '; + } + } + } + $display =~ s/, $//; + $output .= '<li>'.&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]','<i>'.$id.'</i>', + "'$display'")).'</li>'; + } elsif (ref($oldlinkprot->{$id}) eq 'HASH') { + my $oldname = $oldlinkprot->{$id}{'name'}; + $output .= '<li>'.&Apache::lonhtmlcommon::confirm_success(&mt('Deleted setting for [_1]','<i>'."$id ($oldname)".'</i>')).'</li>'; + } + } + } else { + $lti_save_error = 1; + } + } + unless ($lti_save_error) { + foreach my $id (sort { $a <=> $b } keys(%{$changes})) { + unless (ref($changes->{$id}) eq 'HASH') { + push(@deletions,$id); + } + } + if (@deletions) { + if ($context eq 'course') { + &Apache::lonnet::del('nohist_ltienc',\@deletions,$cdom,$cnum); + } + } + } + if ($lti_save_error) { + $output .= '<li>'. + '<span class="LC_error">'. + &mt('An error occurred when saving changes to link protection settings, which remain unchanged.'). + '</span>'. + '</li>'; + } + return $output; +} + sub update_env { my ($cnum,$cdom,$chome,$need_env_update,$storehash) = @_; my $count = 0; @@ -2162,7 +2609,7 @@ 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); @@ -2369,11 +2816,54 @@ function toggleAddmenucoll() { } ENDSCRIPT } + $extresource_js = <<"ENDSCRIPT"; +function toggleExtRes() { + if (document.getElementById('LC_extresource')) { + var extressel = document.getElementById('LC_extresource').value; + if (document.getElementById('LC_extresreusediv')) { + var extresreuse = document.getElementById('LC_extresreusediv'); + if (document.getElementById('LC_extressize')) { + var extressize = document.getElementById('LC_extressize'); + var setvis; + if ((extressel == 'tab') || (extressel == 'window')) { + extresreuse.style.display = 'inline-block'; + setvis = 1; + if (extressel == 'window') { + extressize.style.display = 'inline-block'; + } else { + extressize.style.display = 'none'; + } + } + if (!setvis) { + extresreuse.style.display = 'none'; + extressize.style.display = 'none'; + } + } + } + } +} +ENDSCRIPT + $localization_js = <<"ENDSCRIPT"; +function toggleTimeZone() { + if (document.getElementById('LC_set_timezone')) { + var timezonesel = document.getElementById('LC_set_timezone').value; + if (document.getElementById('LC_tzoverdiv')) { + var tzoverdiv = document.getElementById('LC_tzoverdiv'); + if (timezonesel == '') { + tzoverdiv.style.display = 'none'; + } else { + tzoverdiv.style.display = 'block'; + } + } + } +} +ENDSCRIPT $jscript = '<script type="text/javascript" language="Javascript">'."\n". '// <![CDATA['."\n". $browse_js."\n".$categorize_js."\n".$loncaparev_js."\n". - $cloners_js."\n".$instcode_js. - $syllabus_js."\n".$menuitems_js."\n".'//]]>'."\n". + $cloners_js."\n".$instcode_js."\n".$localization_js."\n". + $syllabus_js."\n".$menuitems_js."\n".$extresource_js."\n". + &linkprot_javascript()."\n".'//]]>'."\n". '</script>'."\n".$stubrowse_js."\n"; return $jscript; } @@ -2459,6 +2949,78 @@ function getIndexByName(item) { 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<radioname.length; i++) { + if (radioname[i].checked == true) { + if (radioname[i].value == 1) { + newdivid.style.display = 'inline-block'; + currdivid.style.display = 'none'; + setvis = 1; + } + break; + } + } + if (!setvis) { + newdivid.style.display = 'none'; + currdivid.style.display = 'inline-block'; + } + } + } + } + return; +} + +function toggleLinkProtExtra(form,item,extra,valon,styleon,num) { + if (document.getElementById('linkprot_'+extra+'_'+num)) { + var extraid = document.getElementById('linkprot_'+extra+'_'+num); + var itemname = form.elements['linkprot_'+item+'_'+num]; + if (itemname) { + if (itemname.length > 0) { + var setvis; + for (var i=0; i<itemname.length; i++) { + if (itemname[i].checked == true) { + if (itemname[i].value == valon) { + extraid.style.display = styleon; + setvis = 1; + } + break; + } + } + if (!setvis) { + extraid.style.display = 'none'; + } + } + } + } + return; +} + +function uncheckLinkProtMakeVis(item,num) { + if (document.getElementById('linkprot_'+item+'_'+num)) { + var currtype = document.getElementById('linkprot_'+item+'_'+num).type; + if (currtype.toLowerCase() == 'checkbox') { + document.getElementById('linkprot_'+item+'_'+num).checked = false; + } + } + return; +} +ENDSCRIPT + +} + sub print_courseinfo { my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype,$noedit) = @_; @@ -3444,10 +4006,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 = '<h4>'. &mt('Requirements for specific folders or resources'). '</h4>'; @@ -3804,7 +4363,7 @@ sub coowner_invitations { @pendingcoown = split(',',$pendingcoowners); } if (ref($currcoownref) eq 'ARRAY') { - @currcoown == @{$currcoownref}; + @currcoown = @{$currcoownref}; } my $disabled; if ($noedit) { @@ -3868,7 +4427,7 @@ sub manage_coownership { @pendingcoown = split(',',$pendingcoowners); } if (ref($currcoownref) eq 'ARRAY') { - @currcoown == @{$currcoownref}; + @currcoown = @{$currcoownref}; } my $disabled; if ($noedit) { @@ -3954,9 +4513,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 .= '<div id="LC_tzoverdiv" style="display:'.$tzsty.';">'. + '<span class="LC_nobreak">'. + &mt('Override individual user preference?'). + &yesno_radio('tzover',$settings,undef,1,'',$noedit). + '</span></div>'; } elsif ($item eq 'datelocale') { my $includeempty = 1; my $locale_obj = &Apache::lonlocal::getdatelocale(); @@ -4076,8 +4649,8 @@ sub print_feedback { } if ($position eq 'top') { my $includeempty = 0; - $datatable .= '</td><td align="right">'. - &user_table($cdom,$item,\@sections, + $datatable .= '</td><td align="right">'. + &user_table($cdom,$item,\@sections, $settings->{$item},\%lt,$noedit); } else { $datatable .= &Apache::lonhtmlcommon::textbox($item.'.text', @@ -4300,8 +4873,8 @@ sub print_discussion { '<table>'.&role_checkboxes($cdom,$cnum,$item,$settings,undef,undef,$noedit). '</table>'; } elsif ($item eq 'plc.users.denied') { - $datatable .= '</td><td align="right">'. - &user_table($cdom,$item,undef, + $datatable .= '</td><td align="right">'. + &user_table($cdom,$item,undef, $settings->{$item},\%lt,$noedit); } elsif ($item eq 'pch.roles.denied') { $datatable .= '</td><td align="right">'. @@ -4671,6 +5244,20 @@ sub print_appearance { text => '<b>'.&mt($itemtext->{'usejsme'}).'</b>', input => 'radio', }, + 'inline_chem' => { + text => '<b>'.&mt($itemtext->{'inline_chem'}).'</b>', + input => 'radio', + }, + 'extresource' => { + text => '<b>'.&mt($itemtext->{'extresource'}).'</b>', + input => 'selectbox', + options => { + iframe => 'In iframe', + tab => 'In new tab', + window => 'In pop-up window', + }, + order => ['iframe','tab','window'], + }, ); return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype,'appearance',$noedit); } @@ -5064,7 +5651,7 @@ sub print_menuitems { my %checked; my $on = ' checked="checked"'; foreach my $key (keys(%{$menu{$num}})) { - if (($key eq 'top') || ($key eq 'inline') || ($key eq 'main')) { + if (($key eq 'top') || ($key eq 'inline') || ($key eq 'foot') || ($key eq 'main')) { if ($menu{$num}{$key} eq 'y') { $checked{$key} = $on; } @@ -5081,7 +5668,13 @@ sub print_menuitems { foreach my $category (@order) { if ((ref($categories{$category}) eq 'ARRAY') && (@{$categories{$category}} > 0)) { $datatable .= '<fieldset style="vertical-align:top; display:inline-block"><legend>'.$menutitles{$category}.'</legend>'."\n"; + if ($category eq 'text') { + $datatable .= '<i>'.&mt('Header').'</i><br />'; + } foreach my $field (@{$categories{$category}}) { + if ($field eq 'disc') { + $datatable .= '<br /><i>'.&mt('Footer').'</i><br />'; + } $datatable .= '<label><input type="checkbox" name="menucollections_'.$num.'" value="'.$field.'"'.$checked{$field}.$disabled.' />'. $menufields{$field}.'</label><br />'; } @@ -5131,8 +5724,8 @@ sub menuitems_abbreviations { sub menuitems_categories { my @order = ('shown','text','links','list','inline'); my %categories = ( - shown => ['top','inline','main'], - text => ['name','role','crs'], + shown => ['top','inline','foot','main'], + text => ['name','role','crs','disc','fdbk'], links => ['pers','logo','menu','comm','roles','help','logout'], list => ['about','prefs','port','wish','anno','rss'], inline => ['cont','grades','chat','people','groups','resv','syll','feeds'], @@ -5143,7 +5736,7 @@ sub menuitems_categories { sub menuitems_titles { return &Apache::lonlocal::texthash ( shown => 'Hierarchy', - text => 'Header text', + text => 'Text', links => 'Header links', list => 'Drop-down list', inline => 'Inline links', @@ -5154,6 +5747,7 @@ sub menuitems_fields { return &Apache::lonlocal::texthash ( top => 'Display header', inline => 'Display inline menu', + foot => 'Display footer', main => 'Access to main menu', pers => 'Personal', logo => 'LON-CAPA', @@ -5165,6 +5759,8 @@ sub menuitems_fields { name => 'Fullname', crs => 'Course Title', role => 'Current Role', + disc => 'Discussion', + fdbk => 'Feedback', about => 'Information', prefs => 'Preferences', port => 'Portfolio', @@ -5206,7 +5802,7 @@ sub menucollections_display { foreach my $num (@current) { my %checked; foreach my $key (keys(%{$menu{$num}})) { - if (($key eq 'top') || ($key eq 'inline') || ($key eq 'main')) { + if (($key eq 'top') || ($key eq 'inline') || ($key eq 'foot') || ($key eq 'main')) { if ($menu{$num}{$key} eq 'y') { $checked{$key} = 1; } @@ -5224,7 +5820,13 @@ sub menucollections_display { if ((ref($categories{$category}) eq 'ARRAY') && (@{$categories{$category}} > 0)) { $output .= '<fieldset style="vertical-align:top; display:inline-block">'. '<legend>'.$menutitles{$category}.'</legend>'."\n"; + if ($category eq 'text') { + $output .= '<b>'.&mt('Header Text').'</b><br /><br />'; + } foreach my $field (@{$categories{$category}}) { + if ($field eq 'disc') { + $output .= '<br /><b>'.&mt('Footer Text').'</b><br /><br />'; + } if ($checked{$field}) { $output .= &Apache::lonhtmlcommon::confirm_success($menufields{$field}); } else { @@ -5243,30 +5845,60 @@ sub menucollections_display { } sub print_linkprotection { - my ($cdom,$settings,$rowtotal,$crstype,$noedit) = @_; - unless (ref($settings) eq 'HASH') { - return; - } + my ($cdom,$cnum,$settings,$rowtotal,$crstype,$noedit,$context) = @_; my %linkprotection; my $count = 0; my $next = 1; - my ($datatable,$disabled,$css_class); + my ($datatable,$disabled,$css_class,$dest); if ($noedit) { $disabled = ' disabled="disabled"'; } - my %lt = &linkprot_names(); + my %desc = &linkprot_names(); + my %lt = &Apache::lonlocal::texthash ( + 'requ' => 'Required settings', + 'opti' => 'Optional settings', + ); my $itemcount = 0; - if (ref($settings->{'linkprotection'}) eq 'HASH') { - if (keys(%{$settings->{'linkprotection'}})) { - my @current = sort { $a <=> $b } keys(%{$settings->{'linkprotection'}}); + my $ltiauth; + if ($context eq 'domain') { + $ltiauth = 1; + } else { + if (exists($env{'course.'.$env{'request.course.id'}.'.internal.ltiauth'})) { + $ltiauth = $env{'course.'.$env{'request.course.id'}.'.internal.ltiauth'}; + } else { + my %domdefs = &Apache::lonnet::get_domain_defaults($cdom); + $ltiauth = $domdefs{'crsltiauth'}; + } + } + if ($context eq 'domain') { + $dest = '/adm/domainprefs'; + } else { + $dest = '/adm/courseprefs'; + } + + my ($switchserver,$switchmessage); + $switchserver = &check_switchserver($cdom,$cnum,$context,$dest); + if ($switchserver) { + if ($context eq 'domain') { + $switchmessage = &mt("submit from domain's primary library server: [_1].",$switchserver); + } elsif ($crstype eq 'Community') { + $switchmessage = &mt("submit from community's home server: [_1].",$switchserver); + } else { + $switchmessage = &mt("submit from course's home server: [_1].",$switchserver); + } + } + + if ((ref($settings) eq 'HASH') && (ref($settings->{'linkprot'}) eq 'HASH')) { + if (keys(%{$settings->{'linkprot'}})) { + my @current = sort { $a <=> $b } keys(%{$settings->{'linkprot'}}); $next += $current[-1]; for (my $i=0; $i<@current; $i++) { my $num = $current[$i]; my %values; - if (ref($settings->{'linkprotection'}->{$num}) eq 'HASH') { - %values = %{$settings->{'linkprotection'}->{$num}}; + if (ref($settings->{'linkprot'}->{$num}) eq 'HASH') { + %values = %{$settings->{'linkprot'}->{$num}}; } else { next; } @@ -5278,24 +5910,117 @@ sub print_linkprotection { $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'. '<label><input type="checkbox" name="linkprot_del" value="'.$i.'"'.$disabled.' />'. - &mt('Delete?').'</label></span></td>'. - '<td><span class="LC_nobreak">'.$lt{'name'}. - ':<input type="text" size="15" name="linkprot_name_'.$i.'" value="'.$values{'name'}.'"'.$disabled.' /></span> '. + &mt('Delete?').'</label></span></td><td>'; + my ($usersty,$onclickrequser,%checkedrequser,$onclickreturnurl,%checkedreturnurl); + if ($ltiauth) { + $usersty = 'display:none'; + $onclickrequser = ' onclick="toggleLinkProtExtra(this.form,'."'requser','optional','1','block','$i'".');"'; + %checkedrequser = ( + no => ' checked="checked"', + yes => '', + ); + if ($values{'requser'}) { + $checkedrequser{'yes'} = $checkedrequser{'no'}; + $checkedrequser{'no'} = ''; + } + $datatable .= '<fieldset><legend>'.$lt{'requ'}.'</legend>'; + if ($values{'requser'}) { + $usersty = 'display:inline-block'; + } + } + $onclickreturnurl = ' onclick="toggleLinkProtExtra(this.form,'."'returnurl','divurlparam','1','inline-block','$i'".');"'; + %checkedreturnurl = ( + no => ' checked="checked"', + yes => '', + ); + if ($values{'returnurl'} ne '') { + $checkedreturnurl{'yes'} = $checkedreturnurl{'no'}; + $checkedreturnurl{'no'} = ''; + } + $datatable .= + '<span class="LC_nobreak">'.$desc{'name'}. + ':<input type="text" size="15" name="linkprot_name_'.$i.'" value="'.$values{'name'}.'" autocomplete="off"'.$disabled.' /></span> '. (' 'x2). - '<span class="LC_nobreak">'.$lt{'version'}.':<select name="linkprot_version_'.$i.'">'. + '<span class="LC_nobreak">'.$desc{'version'}.':<select name="linkprot_version_'.$i.'"'.$disabled.'>'. '<option value="LTI-1p0" '.$selected.'>1.1</option></select></span> '."\n". (' 'x2). - '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" name="linkprot_lifetime_'.$i.'"'. - 'value="'.$values{'lifetime'}.'" size="3"'.$disabled.' /></span>'. - '<br /><br />'. - '<span class="LC_nobreak">'.$lt{'key'}. - ':<input type="text" size="25" name="linkprot_key_'.$i.'" value="'.$values{'key'}.'"'.$disabled.' /></span> '. - (' 'x2). - '<span class="LC_nobreak">'.$lt{'secret'}.':'. - '<input type="password" size="20" name="linkprot_secret_'.$i.'" value="'.$values{'secret'}.'"'.$disabled.' />'. - '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.linkprot_secret_'.$i.'.type='."'text'".' } else { this.form.linkprot_secret_'.$i.'.type='."'password'".' }" />'.&mt('Visible input').'</label>'. - '<input type="hidden" name="linkprot_id_'.$i.'" value="'.$num.'" /></span>'. - '</td></tr>'; + '<span class="LC_nobreak">'.$desc{'lifetime'}.':<input type="text" name="linkprot_lifetime_'.$i.'"'. + ' value="'.$values{'lifetime'}.'" size="3"'.$disabled.' /></span><br /><br />'; + if ($values{'key'} ne '') { + $datatable .= '<span class="LC_nobreak">'.$desc{'key'}; + if ($noedit) { + $datatable .= ': ['.&mt('not shown').']'; + } elsif ($switchserver) { + $datatable .= ': ['.&mt('[_1] to view/edit',$switchserver).']'; + } else { + $datatable .= ':<input type="text" size="25" name="linkprot_key_'.$i.'" value="'.$values{'key'}.'" autocomplete="off"'.$disabled.' />'; + } + $datatable .= '</span> '.(' 'x2); + } elsif (!$switchserver) { + $datatable .= '<span class="LC_nobreak">'.$desc{'key'}.':'. + '<input type="text" size="25" name="linkprot_key_'.$i.'" value="'.$values{'key'}.'" autocomplete="off"'.$disabled.' />'. + '</span> '.(' 'x2); + } + if ($switchserver) { + if ($values{'usable'} ne '') { + $datatable .= '<div id="linkprot_divcurrsecret_'.$i.'" style="display:inline-block" /><span class="LC_nobreak">'. + $desc{'secret'}.': ['.&mt('not shown').'] '.(' 'x2).'</span></div>'. + '<span class="LC_nobreak">'.&mt('Change secret?'). + '<label><input type="radio" value="0" name="linkprot_changesecret_'.$i.'" onclick="javascript:toggleLinkProt(this.form,'."'$i','secret'".');" checked="checked"'.$disabled.' />'.&mt('No').'</label>'. + (' 'x2). + '<label><input type="radio" value="1" name="linkprot_changesecret_'.$i.'" onclick="javascript:toggleLinkProt(this.form,'."'$i','secret'".');" '.$disabled.' />'.&mt('Yes').'</label>'.(' 'x2). + '</span><div id="linkprot_divchgsecret_'.$i.'" style="display:none" />'. + '<span class="LC_nobreak"> - '.$switchmessage.'</span>'. + '</div>'; + } elsif ($values{'key'} eq '') { + $datatable .= '<span class="LC_nobreak">'.&mt('Key and Secret are required').' - '.$switchmessage.'</span>'."\n"; + } else { + $datatable .= '<span class="LC_nobreak">'.&mt('Secret required').' - '.$switchmessage.'</span>'."\n"; + } + $datatable .= '<input type="hidden" name="linkprot_id_'.$i.'" value="'.$num.'" />'; + } else { + if ($values{'usable'} ne '') { + $datatable .= '<div id="linkprot_divcurrsecret_'.$i.'" style="display:inline-block" /><span class="LC_nobreak">'. + $desc{'secret'}.': ['.&mt('not shown').'] '.(' 'x2).'</span></div>'. + '<span class="LC_nobreak">'.&mt('Change?'). + '<label><input type="radio" value="0" name="linkprot_changesecret_'.$i.'" onclick="javascript:toggleLinkProt(this.form,'."'$i','secret'".');" checked="checked"'.$disabled.' />'.&mt('No').'</label>'. + (' 'x2). + '<label><input type="radio" value="1" name="linkprot_changesecret_'.$i.'" onclick="javascript:toggleLinkProt(this.form,'."'$i','secret'".');"'.$disabled.' />'.&mt('Yes'). + '</label> </span><div id="linkprot_divchgsecret_'.$i.'" style="display:none" />'. + '<span class="LC_nobreak">'.&mt('New Secret').':'. + '<input type="password" size="20" name="linkprot_secret_'.$i.'" value="" autocomplete="new-password"'.$disabled.' />'. + '<label><input type="checkbox" name="linkprot_visible_'.$i.'" id="linkprot_visible_'.$i.'" onclick="if (this.checked) { this.form.linkprot_secret_'.$i.'.type='."'text'".' } else { this.form.linkprot_secret_'.$i.'.type='."'password'".' }"'.$disabled.' />'.&mt('Visible input').'</label>'. + '<input type="hidden" name="linkprot_id_'.$i.'" value="'.$num.'" /></span></div>'; + } else { + $datatable .= + '<span class="LC_nobreak">'.$desc{'secret'}.':'. + '<input type="password" size="20" name="linkprot_secret_'.$i.'" value="" autocomplete="new-password"'.$disabled.' />'. + '<label><input type="checkbox" name="linkprot_visible_'.$i.'" id="linkprot_visible_'.$i.'" onclick="if (this.checked) { this.form.linkprot_secret_'.$i.'.type='."'text'".' } else { this.form.linkprot_secret_'.$i.'.type='."'password'".' }"'.$disabled.' />'.&mt('Visible input').'</label>'. + '<input type="hidden" name="linkprot_id_'.$i.'" value="'.$num.'" /></span>'; + } + } + $datatable .= '<br /><br />'. + '<span class="LC_nobreak">'.$desc{'returnurl'}.'?'. + '<label><input type="radio" name="linkprot_returnurl_'.$i.'" value="0"'. + $onclickreturnurl.$checkedreturnurl{'no'}.$disabled.' />'.&mt('No').'</label> '. + '<label><input type="radio" name="linkprot_returnurl_'.$i.'" value="1"'. + $onclickreturnurl.$checkedreturnurl{'yes'}.$disabled.' />'.&mt('Yes').'</label></span>'. + ' </span><div id="linkprot_divurlparam_'.$i.'" style="display:none" />'. + '<span class="LC_nobreak">'.&mt('Parameter name').':'. + '<input type="text" size="15" name="linkprot_urlparam_'.$i.'" value="'.$values{'returnurl'}.'" autocomplete="off"'.$disabled.' />'. + '</span></div> '; + if ($ltiauth) { + $datatable .= (' 'x2).'<span class="LC_nobreak">'.$desc{'requser'}.'?'. + '<label><input type="radio" name="linkprot_requser_'.$i.'" value="0"'. + $onclickrequser.$checkedrequser{'no'}.$disabled.' />'.&mt('No').'</label> '. + '<label><input type="radio" name="linkprot_requser_'.$i.'" value="1"'. + $onclickrequser.$checkedrequser{'yes'}.$disabled.' />'.&mt('Yes').'</label></span>'. + '</fieldset>'. + '<fieldset id="linkprot_optional_'.$i.'" style="'.$usersty.'"><legend>'.$lt{'opti'}.'</legend>'. + &linkprot_options($i,$itemcount,$disabled,\%values,\%desc). + '</fieldset>'; + } + $datatable .= '</td></tr>'; $itemcount ++; } } @@ -5303,34 +6028,189 @@ sub print_linkprotection { $css_class = $itemcount%2?' class="LC_odd_row"':''; $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n". '<input type="hidden" name="linkprot_maxnum" value="'.$next.'" />'."\n". - '<input type="checkbox" name="linkprot_add" value="1" />'.&mt('Add').'</span></td>'."\n". - '<td>'. - '<span class="LC_nobreak">'.$lt{'name'}. - ':<input type="text" size="15" name="linkprot_name_add" value="" /></span> '."\n". + '<input type="checkbox" name="linkprot_add" value="1"'.$disabled.' />'.&mt('Add').'</span></td>'."\n". + '<td width="100%">'; + my ($usersty,$onclickrequser,%checkedrequser,$onclickreturnurl,%checkedreturnurl); + if ($ltiauth) { + $usersty = 'display:none'; + $onclickrequser = ' onclick="toggleLinkProtExtra(this.form,'."'requser','optional','1','block','add'".');"'; + %checkedrequser = ( + no => ' checked="checked"', + yes => '', + ); + $datatable .= '<fieldset><legend>'.$lt{'requ'}.'</legend>'; + } + $onclickreturnurl = ' onclick="toggleLinkProtExtra(this.form,'."'returnurl','divurlparam','1','inline-block','add'".');"'; + %checkedreturnurl = ( + no => ' checked="checked"', + yes => '', + ); + $datatable .= '<span class="LC_nobreak">'.$desc{'name'}. + ':<input type="text" size="15" name="linkprot_name_add" value="" autocomplete="off"'.$disabled.' /></span> '."\n". (' 'x2). - '<span class="LC_nobreak">'.$lt{'version'}.':<select name="linkprot_version_add">'. + '<span class="LC_nobreak">'.$desc{'version'}.':<select name="linkprot_version_add"'.$disabled.'>'. '<option value="LTI-1p0" selected="selected">1.1</option></select></span> '."\n". (' 'x2). - '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" size="3" name="linkprot_lifetime_add" value="300" /></span> '."\n". - '<br /><br />'. - '<span class="LC_nobreak">'.$lt{'key'}.':<input type="text" size="25" name="linkprot_key_add" value="" /></span> '."\n". - (' 'x2). - '<span class="LC_nobreak">'.$lt{'secret'}.':<input type="password" size="20" name="linkprot_secret_add" value="" />'. - '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.linkprot_secret_add.type='."'text'".' } else { this.form.linkprot_secret_add.type='."'password'".' }" />'.&mt('Visible input').'</label></span> '."\n". - '</td></tr>'; + '<span class="LC_nobreak">'.$desc{'lifetime'}.':<input type="text" size="3" name="linkprot_lifetime_add" value="300"'.$disabled.' /></span> '."\n". + '<br /><br />'; + if ($switchserver) { + $datatable .= '<span class="LC_nobreak">'.&mt('Key and Secret are required').' - '.$switchmessage.'</span>'."\n"; + } else { + $datatable .= '<span class="LC_nobreak">'.$desc{'key'}.':<input type="text" size="25" name="linkprot_key_add" value="" autocomplete="off"'.$disabled.' /></span> '."\n". + (' 'x2). + '<span class="LC_nobreak">'.$desc{'secret'}.':<input type="password" size="20" name="linkprot_secret_add" value="" autocomplete="new-password"'.$disabled.' />'. + '<label><input type="checkbox" name="linkprot_visible_add" id="linkprot_visible_add" onclick="if (this.checked) { this.form.linkprot_secret_add.type='."'text'".' } else { this.form.linkprot_secret_add.type='."'password'".' }"'.$disabled.' />'.&mt('Visible input').'</label></span> '."\n"; + } + $datatable .= '<br /><br />'. + '<span class="LC_nobreak">'.$desc{'returnurl'}.'?'. + '<label><input type="radio" name="linkprot_returnurl_add" value="0"'. + $onclickreturnurl.$checkedreturnurl{'no'}.$disabled.' />'.&mt('No').'</label> '. + '<label><input type="radio" name="linkprot_returnurl_add" value="1"'. + $onclickreturnurl.$checkedreturnurl{'yes'}.$disabled.' />'.&mt('Yes').'</label></span>'. + ' </span><div id="linkprot_divurlparam_add" style="display:none" />'. + '<span class="LC_nobreak">'.&mt('Parameter name').':'. + '<input type="text" size="15" name="linkprot_urlparam_add" value="" autocomplete="off"'.$disabled.' />'. + '</span></div> '; + if ($ltiauth) { + $datatable .= (' 'x2).'<span class="LC_nobreak">'.$desc{'requser'}.'?'. + '<label><input type="radio" name="linkprot_requser_add" value="0"'. + $onclickrequser.$checkedrequser{'no'}.$disabled.' />'.&mt('No').'</label> '. + '<label><input type="radio" name="linkprot_requser_add" value="1"'. + $onclickrequser.$checkedrequser{'yes'}.$disabled.' />'.&mt('Yes').'</label></span>'. + '</fieldset>'. + '<fieldset id="linkprot_optional_add" style="'.$usersty.'"><legend>'.$lt{'opti'}.'</legend>'. + &linkprot_options('add',$itemcount,$disabled,{},\%desc). + '</fieldset>'; + } + $datatable .= '</td></tr>'; $$rowtotal ++; - return $datatable;; + return $datatable; } sub linkprot_names { - my %lt = &Apache::lonlocal::texthash( + return &Apache::lonlocal::texthash( 'version' => 'LTI Version', 'key' => 'Key', 'lifetime' => 'Nonce lifetime (s)', - 'name' => 'Launcher Application Name', + 'name' => 'Launcher Application', 'secret' => 'Secret', + 'returnurl' => 'Launcher return URL', + 'requser' => 'Use identity', + 'email' => 'Email address', + 'sourcedid' => 'User ID', + 'other' => 'Other', + 'auth' => 'Display LON-CAPA login page', + 'reject' => 'Discontinue launch process', ); - return %lt; +} + +sub check_switchserver { + my ($cdom,$cnum,$context,$dest) = @_; + my ($allowed,$switchserver,$home); + if ($context eq 'domain') { + $home = &Apache::lonnet::domain($cdom,'primary'); + } else { + $home = &Apache::lonnet::homeserver($cnum,$cdom); + } + unless (($home eq 'no_host') || ($home eq '')) { + my @ids=&Apache::lonnet::current_machine_ids(); + foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } } + if (!$allowed) { + $switchserver='<a href="/adm/switchserver?otherserver='.$home.'&role='. + &HTML::Entities::encode($env{'request.role'},'\'<>"&'). + '&destinationurl='.$dest.'">'.&mt('Switch Server').'</a>'; + } + } + return $switchserver; +} + +sub linkprot_options { + my ($num,$itemcount,$disabled,$current,$desc) = @_; + my %lt; + if (ref($desc) eq 'HASH') { + %lt = %{$desc}; + } + my $userfieldsty = 'none'; + my (%checked,$userfield); + $checked{'sourcedid'} = ' checked="checked"'; + $checked{'reject'} = ' checked="checked"'; + if (ref($current) eq 'HASH') { + if (($current->{'mapuser'} ne '') && ($current->{'mapuser'} ne 'lis_person_sourcedid')) { + $checked{'sourcedid'} = ''; + if ($current->{'mapuser'} eq 'lis_person_contact_email_primary') { + $checked{'email'} = ' checked="checked"'; + } else { + $checked{'other'} = ' checked="checked"'; + $userfield = $current->{'mapuser'}; + $userfieldsty = 'inline-block'; + } + } + if (($current->{'notstudent'} ne '') && ($current->{'notstudent'} ne 'reject')) { + $checked{'reject'} = ''; + $checked{'auth'} = ' checked="checked"'; + } + } + my $onclickuser = ' onclick="toggleLinkProtExtra(this.form,'."'mapuser','userfield','other','inline-block','$num'".');"'; + my $output = '<div class="LC_floatleft"><span class="LC_nobreak">'. + &mt('Source of LON-CAPA username in LTI request').': '; + foreach my $option ('sourcedid','email','other') { + $output .= '<label><input type="radio" name="linkprot_mapuser_'.$num.'" value="'.$option.'"'. + $checked{$option}.$onclickuser.$disabled.' />'.$lt{$option}.'</label>'. + ($option eq 'other' ? '' : (' 'x2) ); + } + $output .= '</span></div>'. + '<div class="LC_floatleft" style="display:'.$userfieldsty.';" id="linkprot_userfield_'.$num.'">'. + '<input type="text" name="linkprot_customuser_'.$num.'" '. + 'value="'.$userfield.'"'.$disabled.' /></div>'; + $output .= '<br />'. + '<div class="LC_floatleft"><span class="LC_nobreak">'. + &mt('Action when username is not for an enrolled student').': '; + foreach my $option ('reject','auth') { + $output .= '<label><input type="radio" name="linkprot_notstudent_'.$num.'" value="'.$option.'"'. + $checked{$option}.$disabled.' />'.$lt{$option}.'</label>'. + ($option eq 'auth' ? '' : (' 'x2) ); + } + $output .= '</span></div>'; + return $output; +} + +sub print_extresource_row { + my ($item,$config,$curr,$noedit) = @_; + my $onchange; + unless ($noedit) { + $onchange = ' onchange="javascript:toggleExtRes();"'; + } + my $id = 'LC_'.$item; + my ($selected,$reuse,$width,$height) = split(/:/,$curr); + my $output = &select_from_options($item,$config->{'order'}, + $config->{'options'},$selected, + $config->{'nullval'}, + undef,undef,$onchange,$noedit,$id); + my ($checked,$reusesty,$sizesty); + if ($reuse) { + $checked = ' checked="checked"'; + } + $reusesty = 'none'; + $sizesty = 'none'; + if (($selected eq 'window') || ($selected eq 'tab')) { + $reusesty = 'inline-block'; + if ($selected eq 'window') { + $sizesty = 'inline-block'; + } + } + $output .= '<div id="LC_extresreusediv" style="display:'.$reusesty.';">'. + '<span class="LC_nobreak">'. + '<label><input type="checkbox" name="extwintabreuse" value="1"'.$checked.'>'. + &mt('Re-use tab/window').'</label>'. + '</span></div>'. + '<fieldset id="LC_extressize" style="display:'.$sizesty.';">'. + '<legend>'.&mt('Window size (optional)').'</legend>'. + '<span class="LC_nobreak">'. + &mt('width').':<input type="text" name="extreswinwidth" value="'.$width.'" size="3" />px'. + (' ' x 3). + &mt('height').':<input type="text" name="extreswinheight" value="'.$height.'" size="3" />px'. + '</span></fieldset>'; + return $output; } sub print_other { @@ -5504,10 +6384,16 @@ sub make_item_rows { (($caller eq 'printouts') && ($item ne 'print_header_format'))) { $colspan = 2; } + my $rowdesc; + if ($caller eq 'appearance') { + $rowdesc = '<span class="LC_nobreak">'.$items->{$item}{text}.'</span>'; + } else { + $rowdesc = $items->{$item}{text}; + } if (exists $items->{$item}{advanced} && $items->{$item}{advanced} == 1) { - $datatable .= &item_table_row_start($items->{$item}{text},$count,"advanced",$colspan); + $datatable .= &item_table_row_start($rowdesc,$count,"advanced",$colspan); } else { - $datatable .= &item_table_row_start($items->{$item}{text},$count,undef,$colspan); + $datatable .= &item_table_row_start($rowdesc,$count,undef,$colspan); } if ($item eq 'defaultcredits') { my $defaultcredits = $env{'course.'.$env{'request.course.id'}.'.internal.defaultcredits'}; @@ -5526,6 +6412,8 @@ sub make_item_rows { $datatable .= &print_hdrfmt_row($item,$settings,$noedit); } elsif ($item eq 'lti.lcmenu') { $datatable .= &lcmenu_checkboxes($cdom,$item,$settings,$crstype,$noedit); + } elsif ($item eq 'extresource') { + $datatable .= &print_extresource_row($item,$items->{$item},$settings->{$item},$noedit); } elsif ($items->{$item}{input} eq 'dates') { my $disabled; if ($noedit) { @@ -5536,7 +6424,7 @@ sub make_item_rows { $settings->{$item},$disabled); } elsif ($items->{$item}{input} eq 'radio') { my ($unsetdefault,$valueyes,$valueno); - if (($item eq 'usejsme') || ($item eq 'uselcmath')) { + if (($item eq 'usejsme') || ($item eq 'uselcmath') || ($item eq 'inline_chem')) { my %domdefs = &Apache::lonnet::get_domain_defaults($cdom); unless ($domdefs{$item} eq '0') { $unsetdefault = 1; @@ -5952,6 +6840,30 @@ sub change_clone { } } } + return; +} + +sub devalidate_remote_courseprefs { + my ($cdom,$cnum,$cachekeys) = @_; + return unless (ref($cachekeys) eq 'HASH'); + my %servers = &Apache::lonnet::internet_dom_servers($cdom); + my %thismachine; + map { $thismachine{$_} = 1; } &Apache::lonnet::current_machine_ids(); + my @posscached = ('courselti'); + if (keys(%servers)) { + foreach my $server (keys(%servers)) { + next if ($thismachine{$server}); + my @cached; + foreach my $name (@posscached) { + if ($cachekeys->{$name}) { + push(@cached,&escape($name).':'.&escape($cdom.'_'.$cnum)); + } + } + if (@cached) { + &Apache::lonnet::remote_devalidate_cache($server,\@cached); + } + } + } return; }