--- loncom/interface/loncommon.pm	2025/01/29 09:11:10	1.1448
+++ loncom/interface/loncommon.pm	2025/02/17 18:30:42	1.1455
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # a pile of common routines
 #
-# $Id: loncommon.pm,v 1.1448 2025/01/29 09:11:10 raeburn Exp $
+# $Id: loncommon.pm,v 1.1455 2025/02/17 18:30:42 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 {
@@ -2300,7 +2309,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 +2320,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 +3075,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 +3094,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 +3120,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 +6947,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 +6970,6 @@ sub bodytag {
                 undef($role);
             }
             unless ($ltimenu->{'coursetitle'}) {
-                $realm='&nbsp;';
                 $showcrstitle = 0;
             }
         }
@@ -6968,7 +6979,6 @@ sub bodytag {
                 undef($role);
             }
             unless ($menuref->{'crs'}) {
-                $realm='&nbsp;';
                 $showcrstitle = 0;
             }
         }
@@ -7036,29 +7046,34 @@ 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<br />|;
+                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" 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">$realm $dc_info</div>|;
+            }
         }
 
         #if directed to not display the secondary menu, don't.  
@@ -7301,6 +7316,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 +7332,12 @@ form, .inline {
     display: inline;
 }
 
+.LC_heading_2 {
+  font-size: 1.17em;
+  margin-top: 1em;
+  margin-bottom: 1em;
+}
+
 .LC_menus_content.shown{
   display: block;
 }
@@ -7323,6 +7350,10 @@ form, .inline {
   text-align:right;
 }
 
+.LC_center {
+  text-align:center;
+}
+
 .LC_middle {
   vertical-align:middle;
 }
@@ -8024,7 +8055,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;
@@ -9140,7 +9171,7 @@ ul#LC_toolbar {
   padding: 0;
   margin: 2px;
   list-style:none;
-  position:relative;
+  display:inline;
   background-color:white;
   overflow: auto;
 }
@@ -9168,6 +9199,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;
@@ -9702,7 +9740,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>';
 }
 
@@ -19043,8 +19085,8 @@ sub needs_coursereinit {
                     $update = 'supp';
                 }
             }
-            return ($update);
         }
+        return ($update);
     }
     return ();
 }
@@ -19575,9 +19617,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;
         }