--- loncom/interface/loncommon.pm	2022/05/24 16:23:03	1.1378
+++ loncom/interface/loncommon.pm	2022/09/08 01:41:13	1.1387
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # a pile of common routines
 #
-# $Id: loncommon.pm,v 1.1378 2022/05/24 16:23:03 raeburn Exp $
+# $Id: loncommon.pm,v 1.1387 2022/09/08 01:41:13 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -61,7 +61,7 @@ use POSIX qw(strftime mktime);
 use Apache::lonmenu();
 use Apache::lonenc();
 use Apache::lonlocal;
-use Apache::lonnet();
+use Apache::lonnavmaps();
 use HTML::Entities;
 use Apache::lonhtmlcommon();
 use Apache::loncoursedata();
@@ -957,8 +957,8 @@ ENDSCRT
 }
 
 sub select_timezone {
-   my ($name,$selected,$onchange,$includeempty,$disabled)=@_;
-   my $output='<select name="'.$name.'" '.$onchange.$disabled.'>'."\n";
+   my ($name,$selected,$onchange,$includeempty,$id,$disabled)=@_;
+   my $output='<select name="'.$name.'" '.$id.$onchange.$disabled.'>'."\n";
    if ($includeempty) {
        $output .= '<option value=""';
        if (($selected eq '') || ($selected eq 'local')) {
@@ -1257,7 +1257,7 @@ END
 
 =pod
 
-=item * &help_open_topic($topic,$text,$stayOnPage,$width,$height,$imgid)
+=item * &help_open_topic($topic,$text,$stayOnPage,$width,$height,$imgid,$links_target)
 
 Returns a string corresponding to an HTML link to the given help
 $topic, where $topic corresponds to the name of a .tex file in
@@ -1281,10 +1281,12 @@ $imgid is the id of the img tag used for
 used in a javascript call to switch the image src.  See 
 lonhtmlcommon::htmlareaselectactive() for an example.
 
+$links_target will optionally be set to a target (_top, _parent or _self).
+
 =cut
 
 sub help_open_topic {
-    my ($topic, $text, $stayOnPage, $width, $height, $imgid) = @_;
+    my ($topic, $text, $stayOnPage, $width, $height, $imgid, $links_target) = @_;
     $text = "" if (not defined $text);
     $stayOnPage = 0 if (not defined $stayOnPage);
     $width = 500 if (not defined $width);
@@ -1307,13 +1309,13 @@ sub help_open_topic {
 
     # Add the text
     my $target = ' target="_top"';
-    if (($env{'request.lti.login'}) && ($env{'request.lti.target'} eq 'iframe')) {
+    if ($links_target) {
+        $target = ' target="'.$links_target.'"';
+    } elsif ((($env{'request.lti.login'}) && ($env{'request.lti.target'} eq 'iframe')) ||
+             (($env{'request.deeplink.login'}) && ($env{'request.deeplink.target'} eq '_self'))) {
         $target = '';
     }
-    if (($env{'request.deeplink.login'}) && ($env{'request.deeplink.target'})) {
-        $target = ' target="'.$env{'request.deeplink.target'}.'"';
-    }
-    if ($text ne "") {	
+    if ($text ne "") {
 	$template.='<span class="LC_help_open_topic">'
                   .'<a'.$target.' href="'.$link.'">'
                   .$text.'</a>';
@@ -1398,20 +1400,20 @@ ENDOUTPUT
 
 # now just updates the help link and generates a blue icon
 sub help_open_menu {
-    my ($topic,$component_help,$faq,$bug,$stayOnPage,$width,$height,$text) 
+    my ($topic,$component_help,$faq,$bug,$stayOnPage,$width,$height,$text,$links_target) 
 	= @_;    
     $stayOnPage = 1;
     my $output;
     if ($component_help) {
 	if (!$text) {
 	    $output=&help_open_topic($component_help,undef,$stayOnPage,
-				       $width,$height);
+				       $width,$height,'',$links_target);
 	} else {
 	    my $help_text;
 	    $help_text=&unescape($topic);
 	    $output='<table><tr><td>'.
 		&help_open_topic($component_help,$help_text,$stayOnPage,
-				 $width,$height).'</td></tr></table>';
+				 $width,$height,'',$links_target).'</td></tr></table>';
 	}
     }
     my $banner_link = &update_help_link($topic,$component_help,$faq,$bug,$stayOnPage);
@@ -1519,26 +1521,25 @@ sub help_open_bug {
 	$link = $url;
     }
 
-    my $target = ' target="_top"';
-    if (($env{'request.lti.login'}) && ($env{'request.lti.target'} eq 'iframe')) {
-        $target = '';
-    }
-    if (($env{'request.deeplink.login'}) && ($env{'request.deeplink.target'})) {
-        $target = ' target="'.$env{'request.deeplink.target'}.'"';
+    my $target = '_top';
+    if ((($env{'request.lti.login'}) && ($env{'request.lti.target'} eq 'iframe')) ||
+        (($env{'request.deeplink.login'}) && ($env{'request.deeplink.target'} eq '_self'))) {
+        $target = '_blank';
     }
+
     # Add the text
     if ($text ne "")
     {
 	$template .= 
   "<table bgcolor='#AA3333' cellspacing='1' cellpadding='1' border='0'><tr>".
-  "<td bgcolor='#FF5555'><a".$target." href=\"$link\"><span style=\"color:#FFFFFF;font-size:10pt;\">$text</span></a>";
+  "<td bgcolor='#FF5555'><a target=\"$target\" href=\"$link\"><span style=\"color:#FFFFFF;font-size:10pt;\">$text</span></a>";
     }
 
     # Add the graphic
     my $title = &mt('Report a Bug');
     my $bugicon=&lonhttpdurl("/adm/lonMisc/smallBug.gif");
     $template .= <<"ENDTEMPLATE";
- <a$target href="$link" title="$title"><img src="$bugicon" border="0" alt="(Bug: $topic)" /></a>
+ <a target="$target" href="$link" title="$title"><img src="$bugicon" border="0" alt="(Bug: $topic)" /></a>
 ENDTEMPLATE
     if ($text ne '') { $template.='</td></tr></table>' };
     return $template;
@@ -5997,7 +5998,7 @@ sub get_domainconf {
                                 foreach my $host (keys(%{$domconfig{'login'}{$key}})) {
                                     if (ref($domconfig{'login'}{$key}{$host}) eq 'HASH') {
                                         $designhash{$udom.'.login.'.$key.'_'.$host} = 1;
-                                        foreach my $item ('text','img','alt','url','title','notsso') {
+                                        foreach my $item ('text','img','alt','url','title','window','notsso') {
                                             $designhash{$udom.'.login.'.$key.'_'.$item.'_'.$host} = $domconfig{'login'}{$key}{$host}{$item};
                                         }
                                     }
@@ -6230,6 +6231,10 @@ sub head_subbox {
 Input: (optional) filename from which breadcrumb trail is built.
        In most cases no input as needed, as $env{'request.filename'}
        is appropriate for use in building the breadcrumb trail.
+       frameset flag
+       If page header is being requested for use in a frameset, then
+       the second (option) argument -- frameset will be true, and
+       the target attribute set for links should be target="_parent".
 
 Returns: HTML div with CSTR path and recent box
          To be included on Authoring Space pages
@@ -6237,7 +6242,7 @@ Returns: HTML div with CSTR path and rec
 =cut
 
 sub CSTR_pageheader {
-    my ($trailfile) = @_;
+    my ($trailfile,$frameset) = @_;
     if ($trailfile eq '') {
         $trailfile = $env{'request.filename'};
     }
@@ -6270,12 +6275,14 @@ sub CSTR_pageheader {
         $title = &mt('Authoring Space');
     }
 
-    my ($target,$crumbtarget) = (' target="_top"','_top'); #FIXME lonpubdir: target="_parent"
-    if (($env{'request.lti.login'}) && ($env{'request.lti.target'} eq 'iframe')) {
+    my ($target,$crumbtarget) = (' target="_top"','_top');
+    if ($frameset) {
+        $target = ' target="_parent"';
+        $crumbtarget = '_parent';
+    } elsif (($env{'request.lti.login'}) && ($env{'request.lti.target'} eq 'iframe')) {
         $target = '';
         $crumbtarget = '';
-    }
-    if (($env{'request.deeplink.login'}) && ($env{'request.deeplink.target'})) {
+    } elsif (($env{'request.deeplink.login'}) && ($env{'request.deeplink.target'})) {
         $target = ' target="'.$env{'request.deeplink.target'}.'"';
         $crumbtarget = $env{'request.deeplink.target'};
     }
@@ -6295,14 +6302,14 @@ sub CSTR_pageheader {
     }
 
     if ($crsauthor) {
-        $output .= '</form>'.&Apache::lonmenu::constspaceform();
+        $output .= '</form>'.&Apache::lonmenu::constspaceform($frameset);
     } else {
         $output .=
              '<br />'
             #FIXME lonpubdir: &Apache::lonhtmlcommon::crumbs($uname.$thisdisfn.'/',$crumbtarget,'/priv','','+1',1)."</b></tt><br />"
             .&Apache::lonhtmlcommon::select_recent('construct','recent','this.form.action=this.form.recent.value;this.form.submit()')
             .'</form>'
-            .&Apache::lonmenu::constspaceform();
+            .&Apache::lonmenu::constspaceform($frameset);
     }
     $output .= '</div>';
 
@@ -6370,6 +6377,21 @@ Inputs:
             context, this will contain a reference to hash of items
             to be included in the page header and/or inline menu.
 
+=item * $menucoll, optional argument, if specific menu collection is in
+            effect, either set as the default for the course, or set for
+            the deeplink paramater for $env{'request.deeplink.login'}
+            then $menucoll will be the number of that collection. 
+
+=item * $menuref, optional argument, reference to a hash, containing the
+            menu options included for the menu in effect, based on the
+            configuration for the numbered menu collection in use.  
+
+=item * $showncrumbsref, reference to a scalar. Calls to lonmenu::innerregister
+            within &bodytag() can result in calls to lonhtmlcommon::breadcrumbs(),
+            if so, $showncrumbsref is set there to 1, and will propagate back
+            via &bodytag() to &start_page(), to prevent lonhtmlcommon::breadcrumbs()
+            being called a second time.
+
 =back
 
 Returns: A uniform header for LON-CAPA web pages.  
@@ -6382,7 +6404,7 @@ other decorations will be returned.
 sub bodytag {
     my ($title,$function,$addentries,$bodyonly,$domain,$forcereg,
         $no_nav_bar,$bgcolor,$args,$advtoolsref,$ltiscope,$ltiuri,
-        $ltimenu,$menucoll,$menuref)=@_;
+        $ltimenu,$menucoll,$menuref,$showncrumbsref)=@_;
 
     my $public;
     if ((($env{'user.name'} eq 'public') && ($env{'user.domain'} eq 'public'))
@@ -6522,7 +6544,8 @@ sub bodytag {
 
         unless ($args->{'no_primary_menu'}) {
             my ($left,$right) = Apache::lonmenu::primary_menu($crstype,$ltimenu,$menucoll,$menuref,
-                                                              $args->{'links_disabled'});
+                                                              $args->{'links_disabled'},
+                                                              $args->{'links_target'});
 
             if ($env{'request.noversionuri'} =~ m{^/res/adm/pages/}) {
                 if ($dc_info) {
@@ -6555,18 +6578,19 @@ sub bodytag {
                 $bodytag .= Apache::lonmenu::secondary_menu($httphost,$ltiscope,$ltimenu,
                                                             $args->{'no_primary_menu'},
                                                             $menucoll,$menuref,
-                                                            $args->{'links_disabled'});
+                                                            $args->{'links_disabled'},
+                                                            $args->{'links_target'});
             }
             $bodytag .= Apache::lonmenu::serverform();
             $bodytag .= Apache::lonhtmlcommon::scripttag('', 'end');
             if ($env{'request.state'} eq 'construct') {
                 $bodytag .= &Apache::lonmenu::innerregister($forcereg,
-                                $args->{'bread_crumbs'},'','',$hostname,$ltiscope,$ltiuri);
+                                $args->{'bread_crumbs'},'','',$hostname,
+                                $ltiscope,$ltiuri,$showncrumbsref);
             } elsif ($forcereg) {
                 $bodytag .= &Apache::lonmenu::innerregister($forcereg,undef,
-                                                            $args->{'group'},
-                                                            $args->{'hide_buttons'},
-                                                            $hostname,$ltiscope,$ltiuri);
+                                $args->{'group'},$args->{'hide_buttons'},
+                                $hostname,$ltiscope,$ltiuri,$showncrumbsref);
             } else {
                 $bodytag .= 
                     &Apache::lonmenu::prepare_functions($env{'request.noversionuri'},
@@ -6650,8 +6674,38 @@ sub endbodytag {
     }
     if ( exists( $env{'internal.head.redirect'} ) ) {
         if (!(ref($args) eq 'HASH' && $args->{'noredirectlink'})) {
+            my ($endbodyjs,$idattr);
+            if ($env{'internal.head.to_opener'}) {
+                my $linkid = 'LC_continue_link';
+                $idattr = ' id="'.$linkid.'"';
+                my $redirect_for_js = &js_escape($env{'internal.head.redirect'});
+                $endbodyjs=<<ENDJS;
+<script type="text/javascript">
+// <![CDATA[
+function ebFunction(evt) {
+    evt.preventDefault();
+    var dest = '$redirect_for_js';
+    if (window.opener != null && !window.opener.closed) {
+        window.opener.location.href=dest;
+        window.close();
+    } else {
+        window.location.href=dest;
+    }
+    return false;
+}
+
+\$(document).ready(function () {
+  if (document.getElementById('$linkid')) {
+    var clickelem = document.getElementById('$linkid');
+    clickelem.addEventListener('click',ebFunction,false);
+  }
+});
+// ]]>
+</script>
+ENDJS
+            }
 	    $endbodytag=
-	        "<br /><a href=\"$env{'internal.head.redirect'}\">".
+	        "$endbodyjs<br /><a href=\"$env{'internal.head.redirect'}\"$idattr>".
 	        &mt('Continue').'</a>'.
 	        $endbodytag;
         }
@@ -8515,6 +8569,10 @@ a#LC_content_toolbar_edittoplevel {
   background-image:url(/res/adm/pages/edittoplevel.gif);
 }
 
+a#LC_content_toolbar_printout {
+  background-image:url(/res/adm/pages/printout.gif);
+}
+
 ul#LC_toolbar li a:hover {
   background-position: bottom center;
 }
@@ -8817,7 +8875,12 @@ Inputs: $title - optional title for the
                                    3- whether the side effect should occur
                            (side effect of setting 
                                $env{'internal.head.redirect'} to the url 
-                               redirected too)
+                               redirected to)
+                                   4- whether the redirect target should be
+                                      the opener of the current (pop-up)
+                                      window (side effect of setting
+                                      $env{'internal.head.to_opener'} to
+                                      1, if true.
             domain         -> force to color decorate a page for a specific
                                domain
             function       -> force usage of a specific rolish color scheme
@@ -8880,15 +8943,43 @@ sub headtag {
         }
     }
     if (ref($args->{'redirect'})) {
-	my ($time,$url,$inhibit_continue) = @{$args->{'redirect'}};
+	my ($time,$url,$inhibit_continue,$to_opener) = @{$args->{'redirect'}};
 	$url = &Apache::lonenc::check_encrypt($url);
 	if (!$inhibit_continue) {
 	    $env{'internal.head.redirect'} = $url;
 	}
-	$result.=<<ADDMETA
+	$result.=<<"ADDMETA";
 <meta http-equiv="pragma" content="no-cache" />
+ADDMETA
+        if ($to_opener) {
+            $env{'internal.head.to_opener'} = 1;
+            my $dest = &js_escape($url);
+            my $timeout = int($time * 1000);
+            $result .=<<"ENDJS";
+<script type="text/javascript">
+// <![CDATA[
+function LC_To_Opener() {
+    var dest = '$dest';
+    if (dest != '') {
+        if (window.opener != null && !window.opener.closed) {
+            window.opener.location.href=dest;
+            window.close();
+        } else {
+            window.location.href=dest;
+        }
+    }
+}
+\$(document).ready(function () {
+    setTimeout('LC_To_Opener()',$timeout);
+});
+// ]]>
+</script>
+ENDJS
+        } else {
+            $result.=<<"ADDMETA";
 <meta http-equiv="Refresh" content="$time; url=$url" />
 ADDMETA
+        }
     } else {
         unless (($args->{'frameset'}) || ($args->{'js_ready'}) || ($args->{'only_body'}) || ($args->{'no_nav_bar'})) {
             my $requrl = $env{'request.uri'};
@@ -9236,6 +9327,7 @@ $args - additional optional args support
              links_disabled -> Links in primary and secondary menus are disabled
                                (Can enable them once page has loaded - see lonroles.pm
                                for an example).
+             links_target   -> Target for links, e.g., _parent (optional).
 
 =back
 
@@ -9324,6 +9416,7 @@ sub start_page {
         }
     }
 
+    my $showncrumbs;
     if (! exists($args->{'skip_phases'}{'body'}) ) {
 	if ($args->{'frameset'}) {
 	    my $attr_string = &make_attr_string($args->{'force_register'},
@@ -9336,7 +9429,8 @@ sub start_page {
                          $args->{'only_body'},      $args->{'domain'},
                          $args->{'force_register'}, $args->{'no_nav_bar'},
                          $args->{'bgcolor'},        $args,
-                         \@advtools,$ltiscope,$ltiuri,\%ltimenu,$menucoll,\%menu);
+                         \@advtools,$ltiscope,$ltiuri,\%ltimenu,$menucoll,
+                         \%menu,\$showncrumbs);
         }
     }
 
@@ -9358,6 +9452,7 @@ sub start_page {
 
     #Breadcrumbs
     if (exists($args->{'bread_crumbs'}) or exists($args->{'bread_crumbs_component'})) {
+        unless ($showncrumbs) {
 		&Apache::lonhtmlcommon::clear_breadcrumbs();
 		#if any br links exists, add them to the breadcrumbs
 		if (exists($args->{'bread_crumbs'}) and ref($args->{'bread_crumbs'}) eq 'ARRAY') {         
@@ -9380,12 +9475,20 @@ sub start_page {
                 } else {
                     undef($menulink);
                 }
+                my $linkprotout;
+                if ($env{'request.deeplink.login'}) {
+                    my $linkprotout = &Apache::lonmenu::linkprot_exit();
+                    if ($linkprotout) {
+                        &Apache::lonhtmlcommon::add_breadcrumb_tool('tools',$linkprotout);
+                    }
+                }
 		#if bread_crumbs_component exists show it as headline else show only the breadcrumbs
 		if(exists($args->{'bread_crumbs_component'})){
 			$result .= &Apache::lonhtmlcommon::breadcrumbs($args->{'bread_crumbs_component'},'',$menulink);
                 } else {
 			$result .= &Apache::lonhtmlcommon::breadcrumbs('','',$menulink);
 		}
+        }
     }
     return $result;
 }
@@ -17341,7 +17444,7 @@ sub init_user_environment {
             my %is_adv = ( is_adv => $env{'user.adv'} );
             my %domdef = &Apache::lonnet::get_domain_defaults($domain);
 
-            foreach my $tool ('aboutme','blog','webdav','portfolio') {
+            foreach my $tool ('aboutme','blog','webdav','portfolio','timezone') {
                 $userenv{'availabletools.'.$tool} = 
                     &Apache::lonnet::usertools_access($username,$domain,$tool,'reload',
                                                       undef,\%userenv,\%domdef,\%is_adv);