--- loncom/interface/loncommon.pm	2025/01/25 17:51:52	1.1446
+++ loncom/interface/loncommon.pm	2025/02/20 03:05:34	1.1459
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # a pile of common routines
 #
-# $Id: loncommon.pm,v 1.1446 2025/01/25 17:51:52 raeburn Exp $
+# $Id: loncommon.pm,v 1.1459 2025/02/20 03:05:34 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -1174,7 +1174,8 @@ sub linked_select_forms {
         $menuorder,
         $onchangefirst,
         $onchangesecond,
-        $suffix
+        $suffix,
+        $haslabel
         ) = @_;
     my $second = "document.$formname.$secondselectname";
     my $first = "document.$formname.$firstselectname";
@@ -1240,13 +1241,18 @@ END
         $result.=">".&mt($hashref->{$value}->{'text'})."</option>\n";
     }
     $result .= "</select>\n";
+    if ($haslabel) {
+        $result .= '</label>';
+    }
     my %select2;
     if (ref($hashref->{$firstdefault}) eq 'HASH') {
         if (ref($hashref->{$firstdefault}->{'select2'}) eq 'HASH') {
             %select2 = %{$hashref->{$firstdefault}->{'select2'}};
         }
     }
-    $result .= $middletext;
+    if ($middletext ne '') {
+        $result .= '<label>'.$middletext;
+    }
     $result .= "<select size=\"1\" name=\"$secondselectname\"";
     if ($onchangesecond) {
         $result .= ' onchange="'.$onchangesecond.'"';
@@ -1264,6 +1270,9 @@ END
         $result.=">".&mt($select2{$value})."</option>\n";
     }
     $result .= "</select>\n";
+    if ($middletext ne '') {
+        $result .= '</label>';
+    }
     #    return $debug;
     return $result;
 }   #  end of sub linked_select_forms {
@@ -1451,7 +1460,7 @@ $banner_link
 <a href="$link" title="$title" $linkattr>$text</a>
 END
     } else {
-        return '&nbsp;'.$text.'&nbsp;';
+        return '&nbsp;<h1 class="LC_helpmenu">'.$text.'</h1>&nbsp;';
     }
 }
 
@@ -1463,6 +1472,10 @@ sub help_menu_js {
     my $helptopic=&general_help();
     my $details_link = $httphost.'/adm/help/'.$helptopic.'.hlp';
     my $nothing=&Apache::lonhtmlcommon::javascript_nothing();
+    my $bannertitle = &mt('Help Menu');
+    &js_escape(\$bannertitle);
+    my $bodytitle = &mt('Documentation');
+    &js_escape(\$bodytitle);
     my $start_page =
         &Apache::loncommon::start_page('Help Menu', undef,
 				       {'frameset'    => 1,
@@ -1474,7 +1487,6 @@ sub help_menu_js {
     my $end_page =
         &Apache::loncommon::end_page({'frameset' => 1,
 				      'js_ready' => 1,});
-
     my $template .= <<"ENDTEMPLATE";
 <script type="text/javascript">
 // <![CDATA[
@@ -1499,8 +1511,8 @@ function helpMenu(target) {
     return;
 }
 function writeHelp(caller) {
-    caller.document.writeln('$start_page\\n<frame name="bannerframe" src="'+banner_link+'" marginwidth="0" marginheight="0" frameborder="0">\\n');
-    caller.document.writeln('<frame name="bodyframe" src="$details_link" marginwidth="0" marginheight="0" frameborder="0">\\n$end_page');
+    caller.document.writeln('$start_page\\n<frame name="bannerframe" title="$bannertitle" src="'+banner_link+'" marginwidth="0" marginheight="0" frameborder="0">\\n');
+    caller.document.writeln('<frame name="bodyframe" title="$bodytitle" src="$details_link" marginwidth="0" marginheight="0" frameborder="0">\\n$end_page');
     caller.document.close();
     caller.focus();
 }
@@ -2300,7 +2312,7 @@ sub import_crsauthor_form {
         dire => 'Directory',
         se   => 'Select',
     );
-    $output = $lt{'dire'}.':&nbsp;'.
+    $output = '<label>'.$lt{'dire'}.':&nbsp;'.
               '<select id="'.$firstselectname.'" name="'.$firstselectname.'" '.
               'onchange="populateCrsSelects(this.form,'."'$firstselectname','$secondselectname',1,'$js_only',0,1,0,0,0".');">'.
               '<option value="" selected="selected">'.$lt{'se'}.'</option>';
@@ -2311,10 +2323,10 @@ sub import_crsauthor_form {
         next if ($key eq '/');
         $output .= '<option value="'.$key.'">'.$key.'</option>'."\n";
     }
-    $output .= '</select><br />'."\n".
+    $output .= '</select></label><br /><label>'."\n".
                $lt{'fnam'}.':&nbsp;<select id="'.$secondselectname.'" name="'.$secondselectname.'">'."\n".
                '<option value="" selected="selected"></option>'."\n".
-               '</select>'."\n".
+               '</select></label>'."\n".
                '<input type="hidden" id="crsres_include_'.$suffix.'" value="'.$only.'" />';
     return ($numdirs,$output);
 }
@@ -3066,7 +3078,7 @@ sub select_level_form {
 
 =pod
 
-=item * &select_dom_form($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms,$excdoms,$disabled)
+=item * &select_dom_form($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms,$excdoms,$disabled,$id)
 
 Returns a string containing a <select name='$name' size='1'> form to 
 allow a user to select the domain to preform an operation in.  
@@ -3085,17 +3097,22 @@ The optional $excdoms is a reference to
 
 The optional $disabled argument, if true, adds the disabled attribute to the select tag.
 
+The option $id argument is the value (if any) to set as the (unique) id attribute for the select tag.
+
 =cut
 
 #-------------------------------------------
 sub select_dom_form {
-    my ($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms,$excdoms,$disabled) = @_;
+    my ($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms,$excdoms,$disabled,$id) = @_;
     if ($onchange) {
         $onchange = ' onchange="'.$onchange.'"';
     }
     if ($disabled) {
         $disabled = ' disabled="disabled"';
     }
+    if ($id ne '') {
+        $id = ' id="'.$id.'"';
+    }
     my (@domains,%exclude);
     if (ref($incdoms) eq 'ARRAY') {
         @domains = sort {lc($a) cmp lc($b)} (@{$incdoms});
@@ -3106,7 +3123,7 @@ sub select_dom_form {
     if (ref($excdoms) eq 'ARRAY') {
         map { $exclude{$_} = 1; } @{$excdoms}; 
     }
-    my $selectdomain = "<select name=\"$name\" size=\"1\"$onchange$disabled>\n";
+    my $selectdomain = "<select name=\"$name\" size=\"1\"$onchange$disabled$id>\n";
     foreach my $dom (@domains) {
         next if ($exclude{$dom});
         $selectdomain.="<option value=\"$dom\" ".
@@ -6933,8 +6950,6 @@ sub bodytag {
         $role = &Apache::lonnet::plaintext($role);
     }
 
-    if (!$realm) { $realm='&nbsp;'; }
-
     my $extra_body_attr = &make_attr_string($forcereg,\%design);
 
 # construct main body tag
@@ -6958,7 +6973,6 @@ sub bodytag {
                 undef($role);
             }
             unless ($ltimenu->{'coursetitle'}) {
-                $realm='&nbsp;';
                 $showcrstitle = 0;
             }
         }
@@ -6968,7 +6982,6 @@ sub bodytag {
                 undef($role);
             }
             unless ($menuref->{'crs'}) {
-                $realm='&nbsp;';
                 $showcrstitle = 0;
             }
         }
@@ -7036,29 +7049,35 @@ END
                                                               $args->{'links_disabled'},
                                                               $args->{'links_target'},
                                                               $collapsible);
-
+            my $labeltext = &HTML::Entities::encode(&mt('Primary links'));
             if ($env{'request.noversionuri'} =~ m{^/res/adm/pages/}) {
                 if ($dc_info) {
                     $dc_info = qq|<span class="LC_cusr_subheading">$dc_info</span>|;
                 }
-                $bodytag .= qq|<div id="LC_nav_bar">$left $role<br />
-                               <em>$realm</em> $dc_info</div>|;
+                $bodytag .= qq|<div id="LC_nav_bar" role="navigation" aria-label="$labeltext">$left $role</div>|;
+                unless (($realm eq '') && ($dc_info eq '')) {
+                    $bodytag .= qq|<div id="LC_realm" role="complementary"><em>$realm</em> $dc_info</div>|;
+                }
                 if ($need_endlcint) {
                     $bodytag .= Apache::lonhtmlcommon::scripttag('', 'end');
                 }
                 return $bodytag;
             }
 
+            $bodytag .= '<div class="LC_landmark" style="margin: 3px 0 0 0;" role="navigation" aria-label="'.$labeltext.'">';
             unless ($env{'request.symb'} =~ m/\.page___\d+___/) {
                 $bodytag .= qq|<div id="LC_nav_bar">$left $role</div>|;
             }
 
-            $bodytag .= $right;
+            $bodytag .= $right.'</div>';
 
             if ($dc_info) {
                 $dc_info = &dc_courseid_toggle($dc_info);
             }
-            $bodytag .= qq|<div id="LC_realm">$realm $dc_info</div>|;
+            unless (($realm eq '') && ($dc_info eq '')) {
+                $bodytag .= qq|<div id="LC_realm" role="complementary">$realm $dc_info</div>|;
+            }
+            $bodytag .= qq|<div style="clear: both; margin: 5px 0 0 0;"></div>|;
         }
 
         #if directed to not display the secondary menu, don't.  
@@ -7071,11 +7090,13 @@ END
         #don't show menus for public users
         if (!$public){
             unless ($args->{'no_inline_menu'}) {
-                $bodytag .= Apache::lonmenu::secondary_menu($httphost,$ltiscope,$ltimenu,
+                $bodytag .= '<div class="LC_landmark" role="navigation" aria-label="Secondary Links">'.
+                            Apache::lonmenu::secondary_menu($httphost,$ltiscope,$ltimenu,
                                                             $args->{'no_primary_menu'},
                                                             $menucoll,$menuref,
                                                             $args->{'links_disabled'},
-                                                            $args->{'links_target'});
+                                                            $args->{'links_target'}).
+                            '</div>'; 
             }
             $bodytag .= Apache::lonmenu::serverform();
             if ($need_endlcint) {
@@ -7090,7 +7111,7 @@ END
                                 $args->{'group'},$args->{'hide_buttons'},
                                 $hostname,$ltiscope,$ltiuri,$showncrumbsref);
             } else {
-                $bodytag .= 
+                $bodytag .=
                     &Apache::lonmenu::prepare_functions($env{'request.noversionuri'},
                                                         $forcereg,$args->{'group'},
                                                         $args->{'bread_crumbs'},
@@ -7099,7 +7120,7 @@ END
         } else {
             # this is to separate menu from content when there's no secondary
             # menu. Especially needed for publicly accessible resources.
-            $bodytag .= '<hr style="clear:both" />';
+            $bodytag .= '<hr style="clear:both" role="complementary" />';
             if ($need_endlcint) {
                 $bodytag .= Apache::lonhtmlcommon::scripttag('', 'end');
             }
@@ -7301,6 +7322,12 @@ form, .inline {
   display: inline;
 }
 
+.LC_landmark {
+  margin: 0;
+  padding: 0;
+  border: none;
+}
+
 .LC_visually_hidden:not(:focus):not(:active) {
     clip-path: inset(50%);
     height: 1px;
@@ -7311,6 +7338,14 @@ form, .inline {
     display: inline;
 }
 
+.LC_heading_2 {
+  font-size: 1.17em;
+}
+
+.LC_heading_3 {
+  font-size: 1.0em;
+}
+
 .LC_menus_content.shown{
   display: block;
 }
@@ -7323,6 +7358,10 @@ form, .inline {
   text-align:right;
 }
 
+.LC_center {
+  text-align:center;
+}
+
 .LC_middle {
   vertical-align:middle;
 }
@@ -7965,39 +8004,68 @@ table.LC_parm_overview_restrictions th {
   border-color: $pgbg;
 }
 
-table#LC_helpmenu {
-  border: none;
-  height: 55px;
-  border-spacing: 0;
+h1.LC_helpmenu {
+  display: inline;
+  font-size: 100%;
+  font-weight: normal;
+  line-height: 1em;
+  margin: 0;
+  padding: 0;
+  border: 0;
 }
 
-table#LC_helpmenu fieldset legend {
-  font-size: larger;
+.LC_helpdesk_headbox {
+  border: 2px groove threedface;
+  padding: 1em;
 }
 
-table#LC_helpmenu_links {
-  width: 100%;
-  border: 1px solid black;
+h1.LC_helpdesk_legend {
+  float: left;
+  margin: -1.7em 0 0;
+  padding: 0 .5em;
   background: $pgbg;
+  font-size: 1em;
+  font-weight: bold;
+}
+
+h1.LC_helpdesk_title {
+  display: inline;
+  font-size: 1em;
+  line-height: 2.5em;
+  margin: 0;
   padding: 0;
-  border-spacing: 1px;
+  vertical-align: bottom;
 }
 
-table#LC_helpmenu_links tr td {
-  padding: 1px;
+.LC_helpdesk_links {
+  border: 1px solid black;
+  padding: 3px;
   background: $tabbg;
   text-align: center;
   font-weight: bold;
+  display: inline;
+  margin-right: -6px;
+}
+
+.LC_helpdesk_img,
+.LC_helpdesk_text {
+  padding: 0;
+  margin: 0;
+  border: 0;
+  display: inline;
 }
 
-table#LC_helpmenu_links a:link,
-table#LC_helpmenu_links a:visited,
-table#LC_helpmenu_links a:active {
+.LC_helpdesk_img a:link,
+.LC_helpdesk_img a:visited,
+.LC_helpdesk_img a:active,
+.LC_helpdesk_text a:link,
+.LC_helpdesk_text a:visited,
+.LC_helpdesk_text a:active {
   text-decoration: none;
   color: $font;
 }
 
-table#LC_helpmenu_links a:hover {
+div.LC_helpdesk_text a:hover {
   text-decoration: underline;
   color: $vlink;
 }
@@ -8024,7 +8092,7 @@ table.LC_pick_box {
   border-spacing: 1px;
 }
 
-table.LC_pick_box td.LC_pick_box_title {
+table.LC_pick_box th.LC_pick_box_title {
   background: $sidebg;
   font-weight: bold;
   text-align: left;
@@ -8228,23 +8296,28 @@ table.LC_prior_tries td {
 }
 
 .LC_prob_status {
-  display: table;
-  padding: 0;
-  margin: 0;
-}
-
-.LC_prob_status_row {
-  display: table-row;
-}
-
-.LC_status_cell {
-  display: table-cell;
+  margin-top: 5px;
   padding-top: 0;
   padding-left: 0;
   padding-bottom: 0;
   padding-right: 5px;
 }
 
+.LC_mail_actions {
+  float: left;
+  padding: 0;
+  margin: 6px;
+}
+
+.LC_vertical_line {
+  width: 1px;
+  background-color: black;
+  height: 4em;
+  float: left;
+  margin: 0;
+  padding: 0;
+}
+
 span.LC_prior_numerical,
 span.LC_prior_string,
 span.LC_prior_custom,
@@ -9135,7 +9208,7 @@ ul#LC_toolbar {
   padding: 0;
   margin: 2px;
   list-style:none;
-  position:relative;
+  display:inline;
   background-color:white;
   overflow: auto;
 }
@@ -9163,6 +9236,13 @@ a.LC_toolbarItem {
   background-color:transparent;
 }
 
+.LC_navtools {
+  display: inline-block;
+  padding: 0;
+  margin: 2px;
+  vertical-align: middle;
+}
+
 ul.LC_funclist {
     margin: 0;
     padding: 0.5em 1em 0.5em 0;
@@ -9697,7 +9777,11 @@ OFFLOAD
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <meta name="apple-mobile-web-app-capable" content="yes" />';
     }
-    $result .= '<meta name="google" content="notranslate" />'."\n";
+    $result .= '<meta name="google" content="notranslate"';
+    if (!$args->{'frameset'}) {
+        $result .= ' /';
+    }
+    $result .= '>'."\n";
     return $result.'</head>';
 }
 
@@ -9828,7 +9912,7 @@ sub xml_begin {
 	    .'xmlns="http://www.w3.org/1999/xhtml">';
     } elsif ($is_frameset) {
         $output='<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">'."\n".
-                '<html>'."\n";
+                '<html lang="en">'."\n";
     } else {
 	$output='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'."\n".
                 '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">'."\n";
@@ -10741,8 +10825,10 @@ sub simple_error_page {
     }
 
     my $page =
-	&Apache::loncommon::start_page($title,'',\%displayargs).
+	&Apache::loncommon::start_page($title,'',\%displayargs)."\n".
+        '<div class="LC_landmark" style="clear:both"  role="main">'.
 	'<p class="LC_error">'.$msg.'</p>'.
+        '</div>'.
 	&Apache::loncommon::end_page();
     if (ref($r)) {
 	$r->print($page);
@@ -19038,8 +19124,8 @@ sub needs_coursereinit {
                     $update = 'supp';
                 }
             }
-            return ($update);
         }
+        return ($update);
     }
     return ();
 }
@@ -19570,9 +19656,9 @@ sub create_captcha {
         if (-e $Apache::lonnet::perlvar{'lonCaptchaDir'}.'/'.$md5sum.'.png') {
             $output = '<input type="hidden" name="crypt" value="'.$md5sum.'" />'."\n".
                       '<span class="LC_nobreak">'.
-                      &mt('Type in the letters/numbers shown below').'&nbsp;'.
+                      '<label>'.&mt('Type in the letters/numbers shown below').'&nbsp;'.
                       '<input type="text" size="5" name="code" value="" autocomplete="new-password" />'.
-                      '</span><br />'.
+                      '</label></span><br />'.
                       '<img src="'.$captcha_params{'www_output_dir'}.'/'.$md5sum.'.png" alt="captcha" />';
             last;
         }