[LON-CAPA-cvs] cvs: loncom /interface courseprefs.pm lonconfigsettings.pm londocs.pm lonextresedit.pm lonexttool.pm

raeburn raeburn at source.lon-capa.org
Fri Mar 14 21:03:33 EDT 2025


raeburn		Sat Mar 15 01:03:33 2025 EDT

  Modified files:              
    /loncom/interface	courseprefs.pm lonconfigsettings.pm londocs.pm 
                     	lonextresedit.pm lonexttool.pm 
  Log:
  - Bug 6754. LON-CAPA as LTI Consumer.
    External Tool definition can include: "Return URL sent on launch", and 
    if Y, value sent can be set in each tool instance in a course.
  
  
-------------- next part --------------
Index: loncom/interface/courseprefs.pm
diff -u loncom/interface/courseprefs.pm:1.133 loncom/interface/courseprefs.pm:1.134
--- loncom/interface/courseprefs.pm:1.133	Tue Jan  7 16:19:19 2025
+++ loncom/interface/courseprefs.pm	Sat Mar 15 01:03:33 2025
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Handler to set configuration settings for a course
 #
-# $Id: courseprefs.pm,v 1.133 2025/01/07 16:19:19 raeburn Exp $
+# $Id: courseprefs.pm,v 1.134 2025/03/15 01:03:33 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -2026,10 +2026,14 @@
             } else {
                 $ltitools{$newid}{'display'}{'target'} = 'iframe';
             }
-            foreach my $item ('passback','roster') {
+            foreach my $item ('passback','roster','returnurl') {
                 if ($env{'form.ltitools_'.$item.'_add'}) {
                     $ltitools{$newid}{$item} = 1;
-                    if ($env{'form.ltitools_'.$item.'valid_add'} ne '') {
+                    if ($item eq 'returnurl') {
+                        if ($env{'form.ltitools_crs'.$item.'_add'}) {
+                            $ltitools{$newid}{'crsconf'}{$item} = 1;
+                        }
+                    } elsif ($env{'form.ltitools_'.$item.'valid_add'} ne '') {
                         my $lifetime = $env{'form.ltitools_'.$item.'valid_add'};
                         $lifetime =~ s/^\s+|\s+$//g;
                         if ($lifetime =~ /^\d+\.?\d*$/) {
@@ -2213,10 +2217,21 @@
                     } else {
                         $haschanges{$itemid} = 1;
                     }
-                    foreach my $extra ('passback','roster') {
+                    foreach my $extra ('passback','roster','returnurl') {
                         if ($env{'form.ltitools_'.$extra.'_'.$i}) {
                             $ltitools{$itemid}{$extra} = 1;
-                            if ($env{'form.ltitools_'.$extra.'valid_'.$i} ne '') {
+                            if ($extra eq 'returnurl') {
+                                if ($env{'form.ltitools_crs'.$extra.'_'.$i}) {
+                                    $ltitools{$itemid}{'crsconf'}{$extra} = 1;
+                                    if (ref($values->{$itemid}{'crsconf'}) eq 'HASH') {
+                                        if (!$values->{$itemid}{'crsconf'}{$extra}) {
+                                            $haschanges{$itemid} = 1;
+                                        }
+                                    } else {
+                                        $haschanges{$itemid} = 1;
+                                    }
+                                }
+                            } elsif ($env{'form.ltitools_'.$extra.'valid_'.$i} ne '') {
                                 my $lifetime = $env{'form.ltitools_'.$extra.'valid_'.$i};
                                 $lifetime =~ s/^\s+|\s+$//g;
                                 if ($lifetime =~ /^\d+\.?\d*$/) {
@@ -3341,11 +3356,21 @@
                         $output .= ' '.&mt('None');
                     }
                     $output .= '</li>';
-                    foreach my $item ('passback','roster') {
+                    foreach my $item ('passback','roster','returnurl') {
                         $output .= '<li>'.$lt{$item}.' ';
                         if ($changes->{$itemid}{$item}) {
                             $output .= &mt('Yes');
-                            if ($changes->{$itemid}{$item.'valid'}) {
+                            if ($item eq 'returnurl') {
+                                if (ref($changes->{$itemid}{'crsconf'}) eq 'HASH') {
+                                    $output .= ' ['.&mt('Configurable in course').': ';
+                                    if ($changes->{$itemid}{'crsconf'}{$item}) {
+                                        $output .= &mt('Yes');
+                                    } else {
+                                        $output .= &mt('No');
+                                    }
+                                    $output .= ']';
+                                }
+                            } elsif ($changes->{$itemid}{$item.'valid'}) {
                                 if ($item eq 'passback') {
                                     $output .= ' '.&mt('valid for at least [quant,_1,day] after launch',
                                                        $changes->{$itemid}{$item.'valid'});
@@ -6627,22 +6652,35 @@
                           '<div class="LC_left_float">'.$lt{'linktext'}.'<br />'.
                           '<input type="text" name="ltitools_linktext_'.$i.'" size="25" value="'.$currdisp{'linktext'}.'" /></div>'.
                           '<div class="LC_left_float">'.$lt{'explanation'}.'<br />'.
-                          '<textarea name="ltitools_explanation_'.$i.'" rows="5" cols="40">'.$currdisp{'explanation'}.
+                          '<textarea name="ltitools_explanation_'.$i.'" rows="5" cols="30">'.$currdisp{'explanation'}.
                           '</textarea></div><div style=""></div><br />';
             my %units = (
                           'passback' => 'days',
                           'roster'   => 'seconds',
                         );
-            foreach my $extra ('passback','roster') {
+            my %courseconfig;
+            if (ref($settings->{$item}) eq 'HASH') {
+                if (ref($settings->{$item}->{'crsconf'}) eq 'HASH') {
+                    %courseconfig = %{$settings->{$item}->{'crsconf'}};
+                }
+            }
+            foreach my $extra ('passback','roster','returnurl') {
                 my $validsty = 'none';
                 my $currvalid;
                 my $checkedon = '';
                 my $checkedoff = ' checked="checked"';
+                my $crscheckedon = '';
+                my $crscheckedoff = ' checked="checked"';
                 if ($settings->{$item}->{$extra}) {
                     $checkedon = $checkedoff;
                     $checkedoff = '';
                     $validsty = 'inline-block';
-                    if ($settings->{$item}->{$extra.'valid'} =~ /^\d+\.?\d*$/) {
+                    if ($extra eq 'returnurl') {
+                        if ($courseconfig{$extra}) {
+                            $crscheckedon = ' checked="checked"';
+                            $crscheckedoff = '';
+                        }
+                    } elsif ($settings->{$item}->{$extra.'valid'} =~ /^\d+\.?\d*$/) {
                         $currvalid = $settings->{$item}->{$extra.'valid'};
                     }
                 }
@@ -6651,12 +6689,21 @@
                               '<label><input type="radio" name="ltitools_'.$extra.'_'.$i.'" value="0"'.$checkedoff.$onclick.' />'.
                               &mt('No').'</label>'.(' 'x2).
                               '<label><input type="radio" name="ltitools_'.$extra.'_'.$i.'" value="1"'.$checkedon.$onclick.' />'.
-                              &mt('Yes').'</label></span></div>'.
-                              '<div class="LC_floatleft" style="display:'.$validsty.';" id="ltitools_'.$extra.'time_'.$i.'">'.
-                              '<span class="LC_nobreak">'.
-                              &mt("until at least [_1] $units{$extra} after launch",
-                                  '<input type="text" name="ltitools_'.$extra.'valid_'.$i.'" value="'.$currvalid.'" />').
-                              '</span></div><div style="padding:0;clear:both;margin:0;border:0"></div>';
+                              &mt('Yes').'</label></span></div>';
+                if ($extra eq 'returnurl') {
+                    $datatable .= '<div class="LC_floatleft" style="display:'.$validsty.';" id="ltitools_course'.$extra.'_'.$i.'">'.
+                                  '<span class="LC_nobreak"> -- '.&mt('configurable in course').': '.
+                                  '<label><input type="radio" name="ltitools_crs'.$extra.'_'.$i.'" value="0"'.$crscheckedoff.' />'.
+                                  &mt('No').'</label>'.(' 'x2).
+                                  '<label><input type="radio" name="ltitools_crs'.$extra.'_'.$i.'" value="1"'.$crscheckedon.' />'.
+                                  &mt('Yes').'</label>';
+                } else {
+                    $datatable .= '<div class="LC_floatleft" style="display:'.$validsty.';" id="ltitools_'.$extra.'time_'.$i.'">'.
+                                  '<span class="LC_nobreak">'.
+                                  &mt("until at least [_1] $units{$extra} after launch",
+                                      '<input type="text" name="ltitools_'.$extra.'valid_'.$i.'" value="'.$currvalid.'" />');
+                }
+                $datatable .= '</span></div><div style="padding:0;clear:both;margin:0;border:0"></div>';
             }
             $datatable .= '<span class="LC_nobreak">'.$lt{'icon'}.': ';
             if ($imgsrc) {
@@ -6742,14 +6789,8 @@
                 }
                 $datatable .= '</select></td>';
             }
-            $datatable .= '</tr></table></fieldset>';
-            my %courseconfig;
-            if (ref($settings->{$item}) eq 'HASH') {
-                if (ref($settings->{$item}->{'crsconf'}) eq 'HASH') {
-                    %courseconfig = %{$settings->{$item}->{'crsconf'}};
-                }
-            }
-            $datatable .= '<fieldset><legend>';
+            $datatable .= '</tr></table></fieldset>'."\n".
+                          '<fieldset><legend>';
             if ($context eq 'domain') {
                 $datatable .= &mt('Configurable in course');
             } else {
@@ -6776,14 +6817,14 @@
                                       '<label><input type="checkbox" name="ltitools_customdel_'.$i.'" value="'.
                                       $key.'" />'.&mt('Delete').'</label></span></td><td>'.$key.'</td>'.
                                       '<td><input type="text" name="ltitools_customval_'.$key.'_'.$i.'"'.
-                                      ' value="'.$custom{$key}.'" /></td></tr>';
+                                      ' value="'.$custom{$key}.'" size="35" /></td></tr>';
                     }
                 }
             }
             $datatable .= '<tr><td><span class="LC_nobreak">'.
                           '<label><input type="checkbox" name="ltitools_customadd" value="'.$i.'" />'.
                           &mt('Add').'</label></span></td><td><input type="text" name="ltitools_custom_name_'.$i.'" />'.
-                          '</td><td><input type="text" name="ltitools_custom_value_'.$i.'" /></td></tr>';
+                          '</td><td><input type="text" name="ltitools_custom_value_'.$i.'" size="35" /></td></tr>';
             $datatable .= '</table></fieldset></td></tr>'."\n";
             $itemcount ++;
         }
@@ -6857,18 +6898,27 @@
                      'passback' => '7',
                      'roster'   => '300',
                    );
-    foreach my $extra ('passback','roster') {
+    foreach my $extra ('passback','roster','returnurl') {
         my $onclick = ' onclick="toggleLTITools(this.form,'."'$extra','add'".');"';
         $datatable .= '<div class="LC_floatleft"><span class="LC_nobreak">'.$lt{$extra}.' '.
                       '<label><input type="radio" name="ltitools_'.$extra.'_add" value="0" checked="checked"'.$onclick.' />'.
                       &mt('No').'</label></span>'.(' 'x2).'<span class="LC_nobreak">'.
                       '<label><input type="radio" name="ltitools_'.$extra.'_add" value="1"'.$onclick.' />'.
-                      &mt('Yes').'</label></span></div>'.
-                      '<div class="LC_floatleft" style="display:none;" id="ltitools_'.$extra.'time_add">'.
-                      '<span class="LC_nobreak">'.
-                      &mt("until at least [_1] $units{$extra} after launch",
-                          '<input type="text" name="ltitools_'.$extra.'valid_add" value="'.$defaulttimes{$extra}.'" />').
-                      '</span></div><div style="padding:0;clear:both;margin:0;border:0"></div>';
+                      &mt('Yes').'</label></span></div>';
+        if ($extra eq 'returnurl') {
+            $datatable .= '<div class="LC_floatleft" style="display:none;" id="ltitools_course'.$extra.'_add">'.
+                          '<span class="LC_nobreak"> -- '.&mt('configurable in course').': '.
+                          '<label><input type="radio" name="ltitools_crs'.$extra.'_add" value="0" checked="checked" />'.
+                          &mt('No').'</label>'.(' 'x2).
+                          '<label><input type="radio" name="ltitools_crs'.$extra.'_add" value="1" />'.
+                          &mt('Yes').'</label>';
+        } else {
+            $datatable .= '<div class="LC_floatleft" style="display:none;" id="ltitools_'.$extra.'time_add">'.
+                          '<span class="LC_nobreak">'.
+                          &mt("until at least [_1] $units{$extra} after launch",
+                              '<input type="text" name="ltitools_'.$extra.'valid_add" value="'.$defaulttimes{$extra}.'" />');
+        }
+        $datatable .= '</span></div><div style="padding:0;clear:both;margin:0;border:0"></div>';
     }
     $datatable .= '<span class="LC_nobreak">'.$lt{'icon'}.': '.
                   '('.&mt('if larger than 21x21 pixels, image will be scaled').') ';
@@ -6965,6 +7015,7 @@
                                           'explanation'    => 'Default Explanation',
                                           'passback'       => 'Tool can return grades:',
                                           'roster'         => 'Tool can retrieve roster:',
+                                          'returnurl'      => 'Return URL sent on launch:',
                                           'crstarget'      => 'Display target',
                                           'crslabel'       => 'Course label',
                                           'crstitle'       => 'Course title',
Index: loncom/interface/lonconfigsettings.pm
diff -u loncom/interface/lonconfigsettings.pm:1.73 loncom/interface/lonconfigsettings.pm:1.74
--- loncom/interface/lonconfigsettings.pm:1.73	Sun Jul 14 16:05:27 2024
+++ loncom/interface/lonconfigsettings.pm	Sat Mar 15 01:03:33 2025
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Handler to set domain-wide configuration settings
 #
-# $Id: lonconfigsettings.pm,v 1.73 2024/07/14 16:05:27 raeburn Exp $
+# $Id: lonconfigsettings.pm,v 1.74 2025/03/15 01:03:33 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -269,6 +269,7 @@
             if (grep(/^ltitools$/, at actions)) {
                 $onload .= "toggleLTITools(document.display,'passback','add');".
                            "toggleLTITools(document.display,'roster','add');".
+                           "toggleLTITools(document.display,'returnurl','add');".
                            "toggleLTITools(document.display,'user','add');";
                 if (ref($values) eq 'HASH') {
                     if (ref($values->{'ltitools'}) eq 'HASH') {
@@ -276,6 +277,7 @@
                         for (my $i=0; $i<$numltitools; $i++) {
                             $onload .= "toggleLTITools(document.display,'passback','$i');".
                                        "toggleLTITools(document.display,'roster','$i');".
+                                       "toggleLTITools(document.display,'returnurl','$i');".
                                        "toggleLTITools(document.display,'user','$i');";
                         }
                     }
@@ -1118,9 +1120,13 @@
 function toggleLTITools(form,setting,item) {
     var radioname = '';
     var divid = '';
-    if ((setting == 'passback') || (setting == 'roster')) {
+    if ((setting == 'passback') || (setting == 'roster') || (setting == 'returnurl')) {
         radioname = 'ltitools_'+setting+'_'+item;
-        divid = 'ltitools_'+setting+'time_'+item;
+        if (setting == 'returnurl') {
+            divid = 'ltitools_course'+setting+'_'+item;
+        } else {
+            divid = 'ltitools_'+setting+'time_'+item;
+        }
         var num = form.elements[radioname].length;
         if (num) {
             var setvis = '';
Index: loncom/interface/londocs.pm
diff -u loncom/interface/londocs.pm:1.726 loncom/interface/londocs.pm:1.727
--- loncom/interface/londocs.pm:1.726	Fri Feb 28 01:07:59 2025
+++ loncom/interface/londocs.pm	Sat Mar 15 01:03:33 2025
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Documents
 #
-# $Id: londocs.pm,v 1.726 2025/02/28 01:07:59 raeburn Exp $
+# $Id: londocs.pm,v 1.727 2025/03/15 01:03:33 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -1704,7 +1704,7 @@
                 my $marker = $2;
                 my $info = $3;
                 my ($toolid,$toolprefix,$tooltype,%toolhash,%toolsettings);
-                my @extras = ('linktext','explanation','crslabel','crstitle','crsappend');
+                my @extras = ('linktext','explanation','crslabel','crstitle','crsappend','returnurl','backtourl');
                 my @toolinfo = split(/:/,$info);
                 if ($residx) {
                     %toolsettings=&Apache::lonnet::dump('exttool_'.$marker,$coursedom,$coursenum);
@@ -1721,7 +1721,8 @@
                 $toolid =~ s/\D//g;
                 ($toolhash{'target'},$toolhash{'width'},$toolhash{'height'},
                  $toolhash{'linktext'},$toolhash{'explanation'},$toolhash{'crslabel'},
-                 $toolhash{'crstitle'},$toolhash{'crsappend'},$toolhash{'gradable'}) = @toolinfo;
+                 $toolhash{'crstitle'},$toolhash{'crsappend'},$toolhash{'gradable'},
+                 $toolhash{'returnurl'},$toolhash{'backtourl'}) = @toolinfo;
                 foreach my $item (@extras) {
                     $toolhash{$item} = &unescape($toolhash{$item});
                 }
@@ -1808,6 +1809,14 @@
                                         }
                                     }
                                 }
+                                if ($tools{'crsconf'}{'returnurl'}) {
+                                    unless ($toolhash{'returnurl'} eq 'custom') {
+                                        delete($toolhash{'backtourl'});
+                                    }
+                                } else {
+                                    delete($toolhash{'returnurl'});
+                                    delete($toolhash{'backtourl'});
+                                }
                             }
                             if ($toolhash{'passback'}) {
                                 my $gradesecret = UUID::Tiny::create_uuid_as_string(UUID_V4);
@@ -1836,6 +1845,14 @@
                                     }
                                 }
                             }
+                            if ($residx) {
+                                if (($toolsettings{'backtourl'} ne '') && (!exists($toolhash{'backtourl'}))) {
+                                    push(@deleted,'backtourl');
+                                }
+                                if (($toolsettings{'returnurl'} ne '') && (!exists($toolhash{'returnurl'}))) {
+                                    push(@deleted,'returnurl');
+                                }
+                            }
                             my $putres = &Apache::lonnet::put('exttool_'.$marker,\%toolhash,$coursedom,$coursenum);
                             if ($putres eq 'ok') {
                                 if (@deleted) {
Index: loncom/interface/lonextresedit.pm
diff -u loncom/interface/lonextresedit.pm:1.35 loncom/interface/lonextresedit.pm:1.36
--- loncom/interface/lonextresedit.pm:1.35	Mon Feb  3 22:52:36 2025
+++ loncom/interface/lonextresedit.pm	Sat Mar 15 01:03:33 2025
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Documents
 #
-# $Id: lonextresedit.pm,v 1.35 2025/02/03 22:52:36 raeburn Exp $
+# $Id: lonextresedit.pm,v 1.36 2025/03/15 01:03:33 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -309,12 +309,13 @@
     my ($marker,$cdom,$cnum,$supplementalflag,$args) = @_;
     my (%newhash,$changed,$newgradable, at deleted,$errormsg);
     ($newhash{'target'},$newhash{'width'},$newhash{'height'},$newhash{'linktext'},$newhash{'explanation'},
-     $newhash{'crslabel'},$newhash{'crstitle'},$newhash{'crsappend'},$newhash{'gradable'}) = split(/:/,$args);
-    foreach my $item ('linktext','explanation','crslabel','crstitle','crsappend') {
+     $newhash{'crslabel'},$newhash{'crstitle'},$newhash{'crsappend'},$newhash{'gradable'},
+     $newhash{'returnurl'},$newhash{'backtourl'}) = split(/:/,$args);
+    foreach my $item ('linktext','explanation','crslabel','crstitle','crsappend','backtourl') {
         $newhash{$item} = &unescape($newhash{$item});
     }
     my %toolhash=&Apache::lonnet::dump('exttool_'.$marker,$cdom,$cnum);
-    foreach my $item ('target','width','height','linktext','explanation','crslabel','crstitle','crsappend','gradable') {
+    foreach my $item ('target','width','height','linktext','explanation','crslabel','crstitle','crsappend','gradable','returnurl','backtourl') {
         $newhash{$item} =~ s/^\s+//;
         $newhash{$item} =~ s/\s+$//;
         if (($item eq 'width') || ($item eq 'height') || ($item eq 'linktext') || ($item eq 'explanation')) {
@@ -329,6 +330,10 @@
             unless ($newhash{$item} == 1) {
                 $newhash{$item} = '';
             }
+        } elsif ($item eq 'backtourl') {
+            unless ($newhash{'returnurl'} eq 'custom') {
+                $newhash{$item} = '';
+            }
         }
         if ($toolhash{$item} ne $newhash{$item}) {
             if (($item eq 'gradable') && (!$supplementalflag)) {
@@ -352,7 +357,7 @@
                 }
             } else {
                 $toolhash{$item} = $newhash{$item};
-                $changed = 1; 
+                $changed = 1;
             }
         }
     }
@@ -396,16 +401,17 @@
     }
     my ($formname,$formid,$toggle,$fieldsetid,$urlid,$subdivid,$dispdivstyle,$dimendivstyle,
         $windivstyle,$linktextstyle,$explanationstyle,$labelstyle,$titlestyle,
-        $appendstyle,$gradablestyle,$subdivstyle,$legend,$urlelem,$toolelem,%toolattr);
+        $appendstyle,$gradablestyle,$returnurlstyle,$subdivstyle,$legend,$urlelem,
+        $toolelem,%toolattr);
     $formname = 'new'.$type;
     $toggle = $type;
     $fieldsetid = 'external'.$type.'form';
     $urlid = $type.'url';
     map { $toolattr{$_} = $type.$_; } ('dispdiv','dimendiv','dimenwidth','dimenheight',
                                        'crstitlediv','crslabeldiv','crsappenddiv',
-                                       'gradablediv','crstitle','crslabel','crsappend',
-                                       'windiv','linktextdiv','explanationdiv',
-                                       'linktext','explanation','providerurl');
+                                       'gradablediv','returnurldiv','crstitle','crslabel',
+                                       'crsappend','windiv','linktextdiv','explanationdiv',
+                                       'linktext','explanation','providerurl','customreturnurl');
     $dispdivstyle = 'display:none';
     $dimendivstyle = 'display:none';
     $windivstyle = 'display:none';
@@ -415,6 +421,7 @@
     $titlestyle = 'display:none';
     $appendstyle = 'display:none';
     $gradablestyle = 'display:none';
+    $returnurlstyle = 'display:none';
     $subdivstyle = 'display:block';
     if ($supplementalflag) {
         $formname = 'newsupp'.$type;
@@ -425,7 +432,8 @@
     }
     my ($link,$legend,$active,$srcclass,$extsrc,$preview,$title,$save,$crstitle,$crslabel,
         $crsappend,$fieldsetstyle,$action,$hiddenelem,$form,$width,$height,$tooltarget,
-        $linktext,$explanation,$providerurl,$chkgrd,$chknogrd,%chkstate);
+        $linktext,$explanation,$providerurl,$returnurl,$chkgrd,$chknogrd,%chkstate,
+        $chknoreturn,$chkreturndef,$chkreturncust,$customreturn,$backtourl);
     $fieldsetstyle = 'display: none;';
     $action = '/adm/coursedocs';
     my $protocol = ($ENV{'SERVER_PORT'} == 443?'https':'http');
@@ -576,6 +584,21 @@
                         if ($ltihash->{'crsconf'}->{'explanation'}) {
                             $explanationstyle = 'padding:0;display:inline';
                         }
+                        if ($ltihash->{'crsconf'}->{'returnurl'}) {
+                            $returnurl = $toolhash{'returnurl'};
+                            $returnurlstyle = 'display:inline';
+                            $backtourl = $toolhash{'backtourl'};
+                            if ($returnurl eq 'none') {
+                                $chknoreturn = ' checked="checked"';
+                                $customreturn = 'hidden';
+                            } elsif (($returnurl eq 'custom') && ($backtourl ne '')) {
+                                $chkreturncust = ' checked="checked"';
+                                $customreturn = 'text';
+                            } else {
+                                $chkreturndef = ' checked="checked"';
+                                $customreturn = 'hidden';
+                            }
+                        }
                     }
                     $toolelem = '<span class="LC_nobreak">'.$image.' '.$tooltitle.'</span><br />';
                     $gradablestyle = 'display:inline';
@@ -658,8 +681,15 @@
             $crslabel = $env{'course.'.$cdom.'_'.$cnum.'.internal.coursecode'};
             $crstitle = $env{'course.'.$cdom.'_'.$cnum.'.description'};
             $crsappend = '';
+            $returnurl = '';
+            $backtourl = '';
+            $customreturn = 'hidden';
             $chknogrd = ' checked="checked"';
+            $chknoreturn = '';
+            $chkreturndef = ' checked="checked"';
+            $chkreturncust = '';
         }
+        my $onclickreturl = ' onclick="updateReturnUrl('."this.form,'$toolattr{'customreturnurl'}','$toolattr{'returnurldiv'}','exttoolreturnurl'".');"';
         $toolelem .= '<div id="'.$toolattr{'dispdiv'}.'" style="'.$dispdivstyle.'">'.
                     '<span class="'.$class.'">'.&mt('Display target:').' '.
                     '<label><input type="radio" name="exttooltarget" value="iframe" '.$chkstate{'iframe'}.'onclick="updateTooldim(this.form,'.
@@ -687,22 +717,32 @@
         $toolelem .= '<div id="'.$toolattr{'crslabeldiv'}.'" style="'.$labelstyle.'">'.
                     '<span class="'.$class.'">'.&mt('Course label:').' '.
                     '<input type="text" id="'.$toolattr{'crslabel'}.'" name="exttoollabel" value="'.$crslabel.'"'.$disabled.' /></span><br />'.
-                    '</div>'.
+                    '</div>'."\n".
                     '<div id="'.$toolattr{'crstitlediv'}.'" style="'.$titlestyle.'">'.
                     '<span class="'.$class.'">'.&mt('Course title:').' '.
                     '<input type="text" id="'.$toolattr{'crstitle'}.'" name="exttooltitle" value="'.$crstitle.'"'.$disabled.' /></span><br />'.
-                    '</div>'.
+                    '</div>'."\n".
                     '<div id="'.$toolattr{'crsappenddiv'}.'" style="'.$appendstyle.'">'.
                     '<span class="'.$class.'">'.&mt('Append to URL[_1]',
                     '<span id="'.$toolattr{'providerurl'}.'"> ('.$providerurl.')<br /></span>').
                     '<input type="text" id="'.$toolattr{'crsappend'}.'" size="30" name="exttoolappend" value="'.$crsappend.'"'.$disabled.' /></span><br />'.
-                    '</div>'.
+                    '</div>'."\n".
                     '<div id="'.$toolattr{'gradablediv'}.'" style="'.$gradablestyle.'">'.
                     '<span class="'.$class.'">'.&mt('Gradable').' '.
                     '<label><input type="radio" name="exttoolgradable" value="1"'.$chkgrd.$disabled.
                     ' />'.&mt('Yes').'</label>'.(' 'x2).
                     '<label><input type="radio" name="exttoolgradable" value="0"'.$chknogrd.$disabled.
-                    ' />'.&mt('No').'</label></span></div>';
+                    ' />'.&mt('No').'</label></span><br /></div>'."\n".
+                    '<div id="'.$toolattr{'returnurldiv'}.'" style="'.$returnurlstyle.'">'.
+                    '<span class="'.$class.'">'.&mt('Include return URL').': '.
+                    '<label><input type="radio" name="exttoolreturnurl" value="none"'.$chknoreturn.$disabled.$onclickreturl.' />'.
+                    &mt('No').'</label>'.(' 'x2).
+                    '<label><input type="radio" name="exttoolreturnurl" value="default"'.$chkreturndef.$disabled.$onclickreturl.' />'.
+                    &mt('Yes, default URL').'</label>'.(' 'x2).
+                    '<label><input type="radio" name="exttoolreturnurl" value="custom"'.$chkreturncust.$disabled.$onclickreturl.' />'.
+                    &mt('Yes, specify URL').'</label></span><br />'."\n".
+                    '<input type="'.$customreturn.'" id="'.$toolattr{'customreturnurl'}.'" size="35" name="exttoolbacktourl" value="'.$backtourl.'"'.$disabled.' />'.
+                    '</div>'."\n";
     }
     my $chooser = $toolelem;
     if ($type eq 'ext') {
@@ -842,7 +882,8 @@
                    "        var ltitoolsExplain = new Array();\n".
                    "        var ltitoolsLabel = new Array();\n".
                    "        var ltitoolsTitle = new Array();\n".
-                   "        var ltitoolsAppend = new Array();\n";
+                   "        var ltitoolsAppend = new Array();\n".
+                   "        var ltitoolsReturnUrl = new Array();\n";
         $exttoolnums = "        var ltitoolsnum = new Array();\n".
                        "        var tooloptval = new Array();\n".
                        "        var toolopttxt = new Array();\n";
@@ -862,7 +903,8 @@
                             "        ltitoolsExplain[$idx] = new Array($num);\n".
                             "        ltitoolsLabel[$idx] = new Array($num);\n".
                             "        ltitoolsTitle[$idx] = new Array($num);\n".
-                            "        ltitoolsAppend[$idx] = new Array($num);\n";
+                            "        ltitoolsAppend[$idx] = new Array($num);\n".
+                            "        ltitoolsReturnUrl[$idx] = new Array($num);\n";
                 my $i=0;
                 foreach my $key (sort { $a <=> $b } keys(%{$toolsref->{$type}})) {
                     if (ref($toolsref->{$type}->{$key}) eq 'HASH') {
@@ -901,6 +943,8 @@
                             $toolsjs .= "         ltitoolsTitle[$idx][$i] = '$title';\n";
                             my $append = $toolsref->{$type}->{$key}->{'crsconf'}->{'append'};
                             $toolsjs .= "         ltitoolsAppend[$idx][$i] = '$append';\n";
+                            my $returnurl = $toolsref->{$type}->{$key}->{'crsconf'}->{'returnurl'};
+                            $toolsjs .= "         ltitoolsReturnUrl[$idx][$i] = '$returnurl';\n";
                         }
                     }
                     $i++;
@@ -1058,10 +1102,12 @@
         var labelinput = prefix+'toolcrslabel';
         var titleinput = prefix+'toolcrstitle';
         var appendinput = prefix+'toolcrsappend';
+        var customreturnurl = prefix+'customreturnurl';
         if (residx > 0) {
             labelinput += '_'+residx;
             titleinput += '_'+residx;
             appendinput += '_'+residx;
+            customreturnurl += '_'+residx;
         }
         if (document.getElementById(labelinput)) {
             var crslabel = document.getElementById(labelinput).value;
@@ -1110,6 +1156,33 @@
         } else {
             info += ':';
         }
+        var returnurldiv = prefix+'toolreturnurldiv';
+        if (residx > 0) {
+            returnurldiv += '_'+residx;
+        }
+        if (document.getElementById(returnurldiv)) {
+            if (document.getElementById(returnurldiv).style.display == 'inline') {
+                if (extform.exttoolreturnurl.length) {
+                    for (var i=0; i<extform.exttoolreturnurl.length; i++) {
+                        if (extform.exttoolreturnurl[i].checked) {
+                            if (extform.exttoolreturnurl[i].value == 'custom') {
+                                var backtourl = extform.exttoolbacktourl.value;
+                                backtourl.trim();
+                                info += ':custom:'+escape(backtourl);
+                            } else if (extform.exttoolreturnurl[i].value == 'default') {
+                                info += ':default:';
+                            } else {
+                                info += ':none:';
+                            }
+                        }
+                    }
+                }
+            } else {
+                info += '::';
+            }
+        } else {
+            info += '::';
+        }
         info=escape(info);
         if (residx > 0) {
             eval("extform.importdetail.value=title+'='+info+'='+residx;extform.submit();");
@@ -1292,6 +1365,7 @@
     titlediv = prefix+'toolcrstitlediv';
     appenddiv = prefix+'toolcrsappenddiv';
     gradablediv = prefix+'toolgradablediv';
+    returnurldiv = prefix+'toolreturnurldiv';
     providerurl = prefix+'toolproviderurl';
     labelinput = prefix+'toolcrslabel';
     titleinput = prefix+'toolcrstitle';
@@ -1332,6 +1406,9 @@
             if (document.getElementById(gradablediv)) {
                 document.getElementById(gradablediv).style.display = 'none';
             }
+            if (document.getElementById(returnurldiv)) {
+                document.getElementById(returnurldiv).style.display = 'none';
+            }
         } else {
             var tooltype = '';
             var typeelem = form.elements[prefix+'exttooltype'];
@@ -1449,6 +1526,13 @@
                                     document.getElementById(gradablediv).style.display = 'inline';
                                 }
                             }
+                            if (document.getElementById(returnurldiv)) {
+                                if (ltitoolsReturnUrl[i][j]) {
+                                    document.getElementById(returnurldiv).style.display = 'inline';
+                                } else {
+                                    document.getElementById(returnurldiv).style.display = 'none';
+                                }
+                            }
                             break;
                         }
                     }
@@ -1458,6 +1542,30 @@
     }
 }
 
+function updateReturnUrl(form,typeid,divid,radioname) {
+    if ((document.getElementById(typeid)) &&
+       (document.getElementById(divid))) {
+        if (document.getElementById(divid).style.display == 'inline') {
+            var radelem = form.elements[radioname];
+            var inputtype = 'hidden';
+            if (radelem.length) {
+                for (var i=0; i<radelem.length; i++) {
+                    if (radelem[i].checked) {
+                        if (radelem[i].value == 'custom') {
+                            inputtype = 'text';
+                        } else {
+                            inputtype = 'hidden';
+                        }
+                        break;
+                    }
+                }
+            }
+            document.getElementById(typeid).type = inputtype;
+        }
+    }
+    return;
+}
+
 function updateTooldim(form,dimendiv,windiv,widthinput,heightinput,linkinput,explaininput) {
     if (form.exttooltarget.length) {
         for (var i=0; i<form.exttooltarget.length; i++) {
Index: loncom/interface/lonexttool.pm
diff -u loncom/interface/lonexttool.pm:1.25 loncom/interface/lonexttool.pm:1.26
--- loncom/interface/lonexttool.pm:1.25	Fri Jun  2 01:20:26 2023
+++ loncom/interface/lonexttool.pm	Sat Mar 15 01:03:33 2025
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Launch External Tool Provider (LTI)
 #
-# $Id: lonexttool.pm,v 1.25 2023/06/02 01:20:26 raeburn Exp $
+# $Id: lonexttool.pm,v 1.26 2025/03/15 01:03:33 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -120,6 +120,22 @@
                 foreach my $item (qw(crslabel crstitle crsappend gradable)) {
                     $toolhash{$item} = $toolsettings{$item};
                 }
+                if ($toolhash{'returnurl'}) {
+                    my $gotreturnurl;
+                    if (ref($toolhash{'crsconf'}) eq 'HASH') {
+                        if ($toolhash{'crsconf'}{'returnurl'}) {
+                            foreach my $item (qw(returnurl backtourl)) {
+                                $toolhash{$item} = $toolsettings{$item};
+                            }
+                            $gotreturnurl = 1;
+                        }
+                    }
+                    unless ($gotreturnurl) {
+                        $toolhash{'returnurl'} = 'default';
+                    }
+                } else {
+                    $toolhash{'returnurl'} = 'none';
+                }
                 $is_tool = 1;
             }
         }
@@ -233,7 +249,7 @@
     my ($r,$cnum,$cdom,$idx,$submittext,$toolsref) = @_;
     my ($version,$context_type,$msgtype,$toolname,$passback,$roster,$locale,
         $crslabel,$crstitle,$gradesecret,$rostersecret,%fields,%rolesmap,
-        %display,%custom, at userlangs,$incdom);
+        %display,%custom, at userlangs,$incdom,$returnurl,$backtourl);
     if (ref($toolsref) eq 'HASH') {
         $version = $toolsref->{'version'};
         $toolname = $toolsref->{'title'};
@@ -257,6 +273,8 @@
         }
         $crslabel = $toolsref->{'crslabel'};
         $crstitle = $toolsref->{'crstitle'};
+        $returnurl = $toolsref->{'returnurl'};
+        $backtourl = $toolsref->{'backtourl'};
     }
     if ($version eq '') {
         $version = 'LTI-1p0';
@@ -304,11 +322,12 @@
     if (scalar(@userlangs) == 1) {
         $locale = $userlangs[0];
     }
-    my ($title,$digest_symb);
+    my ($title,$digest_symb,$digest_suppurl,$resource_link_id);
     my ($symb) = &Apache::lonnet::whichuser();
     if ($symb) {
         $digest_symb = &Encode::decode('UTF-8',$symb);
         $digest_symb = &Digest::SHA::sha1_hex($digest_symb);
+        $resource_link_id = $digest_symb;
         push(@possdigest,$digest_symb);
         my $navmap = Apache::lonnavmaps::navmap->new();
         if (ref($navmap)) {
@@ -317,6 +336,10 @@
                 $title = $res->compTitle();
             }
         }
+    } elsif ($env{'httpref.'.$env{'request.noversionuri'}} eq '/adm/coursedoc') {
+        $digest_suppurl = &Encode::decode('UTF-8',$env{'request.noversionuri'});
+        $digest_suppurl = &Digest::SHA::sha1_hex($digest_suppurl);
+        $resource_link_id = $digest_suppurl;
     }
     my $domdesc = &Apache::lonnet::domain($cdom);
     my $primary_id = &Apache::lonnet::domain($cdom,'primary');
@@ -327,7 +350,7 @@
         lti_version                            => $version,
         lti_message_type                       => $msgtype,
         resource_link_title                    => $title,
-        resource_link_id                       => $digest_symb,
+        resource_link_id                       => $resource_link_id,
         tool_consumer_instance_guid            => $lonhost,
         tool_consumer_instance_description     => $domdesc,
         tool_consumer_info_product_family_code => 'loncapa',
@@ -439,6 +462,51 @@
         $ltiparams{$key} = &Encode::decode('UTF-8',$ltiparams{$key});
     }
     $ltiparams{'basiclti_submit'} = $submittext;
+    if ($returnurl eq 'default') {
+        my $hostname = &Apache::lonnet::hostname($r->dir_config('lonHostID'));
+        my $protocol = 'http';
+        my $port = $r->get_server_port();
+        if ($port eq '443') {
+            $protocol = 'https';
+        }
+        if (&Apache::lonnet::get_proxy_alias()) {
+            my $hdrhost = $r->headers_in->get('Host');
+            if ($hdrhost ne '') {
+                $hostname = $r->headers_in->get('Host');
+            }
+        }
+        my $location = $protocol.'://'.$hostname;
+        if ($display{'target'} eq 'iframe') {
+            my $return_url;
+            if ($symb) {
+                my ($map,$id,$url)=&Apache::lonnet::decode_symb($symb);
+                my $mapurl = &Apache::lonnet::clutter($map);
+                my $mapsymb = &Apache::lonnet::symbread($map);
+                if ((&Apache::lonnet::EXT('resource.0.encrypturl',$mapsymb) =~ /^yes$/i) &&
+                    (!$env{'request.role.adv'})) {
+                    $return_url = &Apache::lonenc::encrypted($mapurl);
+                } else {
+                    $return_url = $mapurl;
+                }
+                $return_url .= '?navmap=1';
+            } elsif ($env{'httpref.'.$env{'request.noversionuri'}} eq '/adm/coursedoc') {
+                $return_url = '/adm/supplemental';
+            } else {
+                $return_url = '/adm/navmaps';
+            }
+            $ltiparams{'launch_presentation_return_url'} = $location.$return_url;
+        } else {
+            my $uri = $env{'request.noversionuri'};
+            if ($env{'request.enc'}) {
+                $uri = &Apache::lonenc::encrypted($uri);
+            }
+            $ltiparams{'launch_presentation_return_url'} = $location.$uri;
+        }
+    } elsif ($returnurl eq 'custom') {
+        if ($backtourl ne '') {
+            $ltiparams{'launch_presentation_return_url'} = $backtourl;
+        }
+    }
     return %ltiparams;
 }
 


More information about the LON-CAPA-cvs mailing list