[LON-CAPA-cvs] cvs: loncom /homework lonhomework.pm /interface loncommon.pm lonmenu.pm
raeburn
raeburn at source.lon-capa.org
Wed Nov 26 14:43:21 EST 2025
raeburn Wed Nov 26 19:43:21 2025 EDT
Modified files:
/loncom/interface loncommon.pm lonmenu.pm
/loncom/homework lonhomework.pm
Log:
- WCAG 2 compliance
Access to items with nested hoverable drop-down lists in Problem Editing
menu (Edit XML mode) by keyboard actions (enter/tab) with aria-expanded
attribute updated accordingly.
-------------- next part --------------
Index: loncom/interface/loncommon.pm
diff -u loncom/interface/loncommon.pm:1.1484 loncom/interface/loncommon.pm:1.1485
--- loncom/interface/loncommon.pm:1.1484 Tue Nov 25 16:54:00 2025
+++ loncom/interface/loncommon.pm Wed Nov 26 19:43:20 2025
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# a pile of common routines
#
-# $Id: loncommon.pm,v 1.1484 2025/11/25 16:54:00 raeburn Exp $
+# $Id: loncommon.pm,v 1.1485 2025/11/26 19:43:20 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -7004,7 +7004,7 @@
}
my @hasdropdowns;
unless ($args->{'no_primary_menu'}) {
- push(@hasdropdowns,'#LC_nav_bar > ol >');
+ push(@hasdropdowns,'#LC_nav_bar > ol >');
}
unless ($args->{'no_secondary_menu'}) {
push(@hasdropdowns,'ul#LC_secondary_menu');
@@ -7013,6 +7013,19 @@
(!$env{'form.selectrole'})) {
push(@hasdropdowns,'div#LC_breadcrumbs ol.LC_primary_menu');
}
+ if ($env{'request.state'} eq "construct") {
+ &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
+ ['problemmode']);
+ if (($env{'form.problemmode'} eq 'editxml') ||
+ ($env{'form.problemmode'} eq 'saveeditxml') ||
+ ($env{'form.problemmode'} eq 'saveviewxml') ||
+ ($env{'form.problemmode'} eq 'undoxml')) {
+ my %editors = &Apache::loncommon::permitted_editors();
+ if (($editors{'xml'}) || ($env{'form.problemmode'} eq 'saveviewxml') || ($env{'form.problemmode'} eq 'undoxml')) {
+ push(@hasdropdowns,'ol#LC_editXML');
+ }
+ }
+ }
if (@hasdropdowns) {
my $jsarray = '["'.join('","', at hasdropdowns).'"]';
$dropdownjs = <<ENDJS;
@@ -7024,24 +7037,26 @@
let tabTimeoutIds = [];
Array.prototype.forEach.call(menuItems, function(el, i){
- el.addEventListener("mouseover", function(event){
+ el.addEventListener("mouseenter", function(event){
while (hoverTimeoutIds.length > 0) {
const timeoutId = hoverTimeoutIds.pop();
clearTimeout(timeoutId);
}
document.querySelectorAll(anc+" li.LC_hoverable.LC_open").forEach(element => {
element.classList.remove("LC_open");
+ element.querySelector('a').setAttribute('aria-expanded',"false");
});
if (!hasClass(this,"LC_open")) {
this.classList.add("LC_open");
+ this.querySelector('a').setAttribute('aria-expanded',"true");
}
});
- el.addEventListener("mouseout", function(event) {
+ el.addEventListener("mouseleave", function(event) {
const timeoutId = setTimeout(function() {
var opennav = document.querySelector(anc+" li.LC_hoverable.LC_open");
if (opennav) {
opennav.classList.remove("LC_open");
- opennav.querySelector('a').setAttribute('aria-expanded', "false");
+ opennav.querySelector('a').setAttribute('aria-expanded',"false");
}
}, 500);
hoverTimeoutIds.push(timeoutId);
@@ -7053,19 +7068,19 @@
clearTimeout(timeoutId);
}
}
+ const anclist = getAllAncestorsWithClass(this,'LC_hoverable');
document.querySelectorAll(anc+" li.LC_hoverable.LC_open").forEach(element => {
- if (element !== this.parentNode) {
+ if (anclist.indexOf(element) == -1) {
element.classList.remove("LC_open");
+ element.querySelector('a').setAttribute('aria-expanded',"false");
}
});
- if (hasClass(this.parentNode,"LC_hoverable")) {
- if (!hasClass(this.parentNode,"LC_open")) {
- this.parentNode.classList.add("LC_open");
- }
- this.setAttribute('aria-expanded', "true");
+ if (!hasClass(this.parentNode,"LC_open")) {
+ this.parentNode.classList.add("LC_open");
+ this.setAttribute('aria-expanded',"true");
} else {
- this.parentNode.add("LC_hoverable");
- this.setAttribute('aria-expanded', "false");
+ this.parentNode.classList.remove("LC_open");
+ this.setAttribute('aria-expanded',"false");
}
event.preventDefault();
});
@@ -7080,9 +7095,11 @@
clearTimeout(timeoutId);
}
}
+ const anclist = getAllAncestorsWithClass(event.target,'LC_hoverable');
document.querySelectorAll(anc+" li.LC_hoverable.LC_open").forEach(element => {
- if (element !== event.target.closest('li.LC_hoverable.LC_open')) {
+ if (anclist.indexOf(element) == -1) {
element.classList.remove("LC_open");
+ element.querySelector('a').setAttribute('aria-expanded',"false");
}
});
});
@@ -7118,6 +7135,20 @@
return new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className);
}
}
+
+function getAllAncestorsWithClass(element, className) {
+ const ancestors = [];
+ let currentElement = element.parentElement; // Start with the immediate parent
+
+ while (currentElement) {
+ if (currentElement.classList.contains(className)) {
+ ancestors.push(currentElement);
+ }
+ currentElement = currentElement.parentElement; // Move up to the next parent
+ }
+ return ancestors;
+}
+
// ]]>
</script>
@@ -8967,21 +8998,20 @@
line-height: 1.5em;
}
-ol.LC_primary_menu li a,
-ol.LC_primary_menu li p {
+ol.LC_primary_menu li a {
display: block;
margin: 0;
padding: 0 5px 0 10px;
text-decoration: none;
}
-ol.LC_primary_menu li p span.LC_primary_menu_innertitle {
+ol.LC_primary_menu li a span.LC_primary_menu_innertitle {
display: inline-block;
width: 95%;
text-align: left;
}
-ol.LC_primary_menu li p span.LC_primary_menu_innerarrow {
+ol.LC_primary_menu li a span.LC_primary_menu_innerarrow {
display: inline-block;
width: 5%;
float: right;
@@ -9002,7 +9032,7 @@
top: 0;
}
-ol.LC_primary_menu li:hover > ul, ol.LC_primary_menu li.hover > ul, ol.LC_primary_menu li.LC_open > ul {
+ol.LC_primary_menu li:hover > ul, ol.LC_primary_menu li.hover > ul, ol.LC_primary_menu li.LC_open > ul {
display: block;
position: absolute;
margin: 0;
@@ -9022,12 +9052,6 @@
border-bottom: 1px solid $data_table_dark;
}
-ol.LC_primary_menu li li p:hover {
- color:$button_hover;
- text-decoration:none;
- background-color:$data_table_dark;
-}
-
ol.LC_primary_menu li li a:hover {
color:$button_hover;
background-color:$data_table_dark;
Index: loncom/interface/lonmenu.pm
diff -u loncom/interface/lonmenu.pm:1.566 loncom/interface/lonmenu.pm:1.567
--- loncom/interface/lonmenu.pm:1.566 Tue Nov 25 16:54:00 2025
+++ loncom/interface/lonmenu.pm Wed Nov 26 19:43:20 2025
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Routines to control the menu
#
-# $Id: lonmenu.pm,v 1.566 2025/11/25 16:54:00 raeburn Exp $
+# $Id: lonmenu.pm,v 1.567 2025/11/26 19:43:20 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -871,9 +871,10 @@
# href is a reference to another submenu
if (ref($href) eq 'ARRAY') {
- $menu .= '<li style="margin:0;padding:0;'.$bordertop . $borderbot . '">';
- $menu .= '<p><span class="LC_primary_menu_innertitle">'
- . $title . '</span><span class="LC_primary_menu_innerarrow">▶</span></p>';
+ $menu .= '<li style="margin:0;padding:0;'.$bordertop . $borderbot . '" class="LC_hoverable">';
+ $menu .= '<a href="#" aria-expanded="false">'
+ .'<span class="LC_primary_menu_innertitle">'
+ . $title . '</span><span class="LC_primary_menu_innerarrow">▶</span></a>';
$menu .= '<ul>';
$menu .= &build_submenu($target, $href, $translate);
$menu .= '</ul>';
Index: loncom/homework/lonhomework.pm
diff -u loncom/homework/lonhomework.pm:1.400 loncom/homework/lonhomework.pm:1.401
--- loncom/homework/lonhomework.pm:1.400 Thu Sep 11 02:06:01 2025
+++ loncom/homework/lonhomework.pm Wed Nov 26 19:43:21 2025
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# The LON-CAPA Homework handler
#
-# $Id: lonhomework.pm,v 1.400 2025/09/11 02:06:01 raeburn Exp $
+# $Id: lonhomework.pm,v 1.401 2025/11/26 19:43:21 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -1336,7 +1336,7 @@
&Apache::structuretags::problem_edit_buttons('editxml');
$result.='<div>';
- $result .= '<ol class="LC_primary_menu" style="display:inline-block;font-size:90%;vertical-align:middle;">';
+ $result .= '<ol id="LC_editXML" class="LC_primary_menu" style="display:inline-block;font-size:90%;vertical-align:middle;">';
my $nocodemirror = &Apache::loncommon::nocodemirror();
unless ($nocodemirror) {
More information about the LON-CAPA-cvs
mailing list