[LON-CAPA-cvs] cvs: loncom /interface lonhtmlcommon.pm lonnotify.pm
raeburn
raeburn at source.lon-capa.org
Mon May 4 20:43:18 EDT 2026
raeburn Tue May 5 00:43:18 2026 EDT
Modified files:
/loncom/interface lonnotify.pm lonhtmlcommon.pm
Log:
- WCAG 2.2 compliance for Domain Coordinator's "Send broadcast e-mail" tool.
- Include labels for form elements.
- Satisfy minimum spacing between touch targets.
- Use <th> tags for column headings and row headings in data table
with scope="row" attribute for latter.
- For form elements in data table cells use aria-labelledby to reference
appropriate column and row headers.
- Group form elements in fieldset with legend for screenreaders.
- Replace use of <table> for layout with <div>.
-------------- next part --------------
Index: loncom/interface/lonnotify.pm
diff -u loncom/interface/lonnotify.pm:1.46 loncom/interface/lonnotify.pm:1.47
--- loncom/interface/lonnotify.pm:1.46 Sat Dec 13 13:33:33 2025
+++ loncom/interface/lonnotify.pm Tue May 5 00:43:17 2026
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Sending messages
#
-# $Id: lonnotify.pm,v 1.46 2025/12/13 13:33:33 raeburn Exp $
+# $Id: lonnotify.pm,v 1.47 2026/05/05 00:43:17 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -215,25 +215,36 @@
$output .= &Apache::lonhtmlcommon::start_pick_box();
$output .= &Apache::lonhtmlcommon::row_title(&mt('Date range'));
- $output .= '<table><tr><td>'.&mt('Earliest to display:').' </td><td>'.
- $startdateform.'</td></tr>';
- $output .= '<tr><td>'.&mt('Latest to display:').' </td><td>'.$enddateform.
- '</td></tr></table>';
+ $output .= '<div class="LC_grid" role="grid" style="margin: 0;">'
+ .'<div class="LC_grid_row" role="row">'
+ .'<div class="LC_grid_cell" role="gridcell">'
+ .&mt('Earliest to display:').' </div>'
+ .'<div class="LC_grid_cell" role="gridcell">'.$startdateform.'</div>'
+ .'</div><div class="LC_grid_row" role="row">'
+ .'<div class="LC_grid_cell" role="gridcell">'
+ .&mt('Latest to display:').' </div>'
+ .'<div class="LC_grid_cell" role="gridcell">'.$enddateform.'</div>'
+ .'</div></div>';
$output .= &Apache::lonhtmlcommon::row_closure();
$output .= &Apache::lonhtmlcommon::row_title(&mt('Choose sender(s)'));
my %personnel = &Apache::lonnet::get_domain_roles($cdom,\@roles);
my @domcc = ();
+ $output .= '<fieldset class="LC_borderless" style="line-height: 185%;">'
+ .'<legend class="LC_visually_hidden">'.&mt('Filter by sender').'</legend>';
foreach my $server (keys(%personnel)) {
foreach my $user (sort(keys(%{$personnel{$server}}))) {
my ($trole,$uname,$udom,$runame,$rudom,$rsec) = split(/:/,$user);
unless (grep/^$uname:$udom$/, at domcc) {
my %userinfo = &Apache::lonnet::get('environment',['lastname','firstname'],$udom,$uname);
- $output .= '<input type="checkbox" name="sender" value="'.$uname.':'.$udom.'" /> '.$userinfo{'firstname'}.' '.$userinfo{'lastname'}.' ('.$uname.':'.$udom.')';
- push (@domcc,$uname.':'.$udom);
+ $output .= '<span class="LC_nobreak"><label>'
+ .'<input type="checkbox" name="sender" value="'.$uname.':'.$udom.'" />'
+ .' '.$userinfo{'firstname'}.' '.$userinfo{'lastname'}.'</label></span>'
+ .' ('.$uname.':'.$udom.') ';
+ push(@domcc,$uname.':'.$udom);
}
}
}
- $output .= &Apache::lonhtmlcommon::row_closure();
+ $output .= '</fieldset>'.&Apache::lonhtmlcommon::row_closure();
$output .= &Apache::lonhtmlcommon::submit_row(&mt('Submit'),$cmd,$submit_text);
$output .= &Apache::lonhtmlcommon::end_pick_box();
$output .= qq(<input type="hidden" name="sortby" value="date" />\n).
@@ -513,6 +524,8 @@
my %lt=&Apache::lonlocal::texthash(
'nore' => 'No recipients identified',
+ 'sele' => 'Select',
+ 'unam' => 'username:domain',
'emad' => 'e-mail address',
);
my %elements = (
@@ -620,34 +633,42 @@
if ($totalrecip > 0) {
$output .= &Apache::lonhtmlcommon::start_pick_box();
- $output .= &Apache::lonhtmlcommon::row_title(&mt('Subject'));
- $output .= '<input type="text" name="subject" size="30" />';
+ $output .= &Apache::lonhtmlcommon::row_title('<label for="subject">'.&mt('Subject').'</label>');
+ $output .= '<input type="text" name="subject" id="subject" size="30" />';
$output .= &Apache::lonhtmlcommon::row_closure();
- $output .= &Apache::lonhtmlcommon::row_title(&mt('Message'));
+ $output .= &Apache::lonhtmlcommon::row_title('<label for="message">'.&mt('Message').'</label>');
$output .= ' <textarea name="message" id="message"
cols="60" rows="10" wrap="hard"></textarea>';
$output .= &Apache::lonhtmlcommon::row_closure();
$output .= &Apache::lonhtmlcommon::row_title(&mt('Recipients'));
- $output .= '<input type="button" value="check all"
- onclick="javascript:checkAll(document.compose.recipient)" />
- <input type="button" value="uncheck all"
- onclick="javascript:uncheckAll(document.compose.recipient)" />
- <br />';
- $output .= &Apache::loncommon::start_data_table();
if (keys(%recipients) > 0) {
- $output .= &Apache::loncommon::start_data_table_header_row();
- $output .= '<th> <th>username:domain</th><th>'.$lt{'emad'}.'</th>';
- $output .= &Apache::loncommon::end_data_table_header_row();
- }
- foreach my $username (sort(keys(%recipients))) {
- $output .= &Apache::loncommon::start_data_table_row();
- if ($recipients{$username} =~ /\@/) {
- my $value=&escape($username).':'.&escape($recipients{$username});
- $output .= '<td><input type="checkbox" name="recipient" value="'.$value.'" /></td><td>'.$username.'</td><td>'.$recipients{$username}.'</td>';
+ $output .= '<input type="button" value="check all"
+ onclick="javascript:checkAll(document.compose.recipient)" />
+ <input type="button" value="uncheck all"
+ onclick="javascript:uncheckAll(document.compose.recipient)" />
+ <br />'
+ .'<fieldset class="LC_borderless" style="line-height: 185%;">'
+ .'<legend class="LC_visually_hidden">'.&mt('Select Recipients').'</legend>'
+ .&Apache::loncommon::start_data_table('LC_paramDefault')
+ .&Apache::loncommon::start_data_table_header_row()
+ .'<th id="colselect">'.$lt{'sele'}.'</th><th>'.$lt{'unam'}.'</th><th>'.$lt{'emad'}.'</th>'
+ .&Apache::loncommon::end_data_table_header_row();
+ my $count = 0;
+ foreach my $username (sort(keys(%recipients))) {
+ $output .= &Apache::loncommon::start_data_table_row();
+ if ($recipients{$username} =~ /\@/) {
+ my $value=&escape($username).':'.&escape($recipients{$username});
+ $output .= '<td><input type="checkbox" name="recipient" value="'.$value.'" aria-labelledby="colselect username'.$count.'"/></td>'.
+ '<th scope="row" class="LC_rowheader" id="username'.$count.'">'.$username.'</th>'.
+ '<td>'.$recipients{$username}.'</td>';
+ }
+ $output .= &Apache::loncommon::end_data_table_row();
+ $count ++;
}
- $output .= &Apache::loncommon::end_data_table_row();
+ $output .= &Apache::loncommon::end_data_table();
+ } else {
+ $output .= &mt('No possible recipients (with email addresses)');
}
- $output .= &Apache::loncommon::end_data_table();
if (@unmatched) {
$output .= '<br /><br />'.&mt('Could not determine e-mail addresses for the following users:').'<ul>';
foreach my $username (sort(@unmatched)) {
@@ -656,11 +677,12 @@
$output .= '</ul>';
}
$output .= &Apache::lonhtmlcommon::row_closure();
- $output .= &Apache::lonhtmlcommon::row_title(&mt('Sender e-mail address'));
- $output .= '<input type="text" name="sender" value="'.$sender.'" />';
+ $output .= &Apache::lonhtmlcommon::row_title('<label for="sender">'.&mt('Sender e-mail address').'</label>');
+ $output .= '<input type="text" name="sender" id="sender" value="'.$sender.'" size="25" />';
$output .= &Apache::lonhtmlcommon::row_closure();
$output .= &Apache::lonhtmlcommon::submit_row(&mt('Submit'),'process',&mt('Send'));
- $output .= &Apache::lonhtmlcommon::end_pick_box();
+ $output .= &Apache::lonhtmlcommon::end_pick_box()
+ .'</fieldset>';
} else {
$output .= $lt{'nore'}."\n".
'<input type="hidden" name="command" value="" />'."\n";
Index: loncom/interface/lonhtmlcommon.pm
diff -u loncom/interface/lonhtmlcommon.pm:1.431 loncom/interface/lonhtmlcommon.pm:1.432
--- loncom/interface/lonhtmlcommon.pm:1.431 Thu Apr 30 00:27:07 2026
+++ loncom/interface/lonhtmlcommon.pm Tue May 5 00:43:17 2026
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# a pile of common html routines
#
-# $Id: lonhtmlcommon.pm,v 1.431 2026/04/30 00:27:07 raeburn Exp $
+# $Id: lonhtmlcommon.pm,v 1.432 2026/05/05 00:43:17 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -2586,7 +2586,7 @@
}
my $output;
if (defined($title)) {
- $output = &row_title($title,$css_class);
+ $output = &row_title('<label for="roles">'.$title.'</label>',$css_class);
}
$output .= qq|
<select name="roles" id="roles" multiple="multiple">\n|;
@@ -2661,26 +2661,34 @@
</script>
|;
- my ($allcrs,$pickspec);
+ my ($allcrs,$pickspec,$filter);
if ($crstype eq 'Community') {
$allcrs = &mt('All communities');
$pickspec = &mt('Pick specific communities:');
+ $filter = &mt('Community filter');
} else {
$allcrs = &mt('All courses');
$pickspec = &mt('Pick specific course(s):');
+ $filter = &mt('Course filter');
}
my $courseform='<b>'.&Apache::loncommon::selectcourse_link
($formname,'pickcourse','pickdomain','coursedesc','',1,$crstype).'</b>';
- $output .= '<label><input type="radio" name="coursepick" value="all" onclick="coursePick(this.form)" />'.$allcrs.'</label><br />';
+ $output .= '<fieldset class="LC_borderless" style="line-height: 185%;">'.
+ '<legend class="LC_visually_hidden">'.$filter.'</legend>'.
+ '<label><input type="radio" name="coursepick" value="all" onclick="coursePick(this.form)" />'.
+ $allcrs.'</label><br />';
if ($totcodes > 0) {
my $numtitles = @$codetitles;
if ($numtitles > 0) {
$output .= '<label><input type="radio" name="coursepick" value="category" onclick="coursePick(this.form);alert('."'".&html_escape(&mt('Choose categories, from left to right'))."'".')" />'.&mt('Pick courses by category:').'</label><br />';
- $output .= '<table><tr><td>'.$$codetitles[0].'<br />'."\n".
- '<select name="'.$standardnames->[0].
- '" onchange="setPick(this.form);courseSet('."'$$codetitles[0]'".')">'."\n".
- ' <option value="-1" />Select'."\n";
+ $output .= '<div class="LC_grid" role="grid">'.
+ '<div class="LC_grid_row" role="row">'.
+ '<div class="LC_grid_cell" role="grid_cell">'.
+ $codetitles->[0].'<br />'."\n".
+ '<select name="'.$standardnames->[0].
+ '" onchange="setPick(this.form);courseSet('."'$codetitles->[0]'".')">'."\n".
+ ' <option value="-1" />Select'."\n";
my @items = ();
my @longitems = ();
if ($$idlist{$$codetitles[0]} =~ /","/) {
@@ -2705,16 +2713,17 @@
for (my $i=0; $i<@items; $i++) {
$output .= ' <option value="'.$items[$i].'">'.$longitems[$i].'</option>';
}
- $output .= '</select></td>';
+ $output .= '</select></div>';
for (my $i=1; $i<$numtitles; $i++) {
- $output .= '<td>'.$$codetitles[$i].'<br />'."\n".
- '<select name="'.$standardnames->[$i].
- '" onchange="courseSet('."'$$codetitles[$i]'".')">'."\n".
- '<option value="-1"><-Pick '.$$codetitles[$i-1].'</option>'."\n".
- '</select>'."\n".
- '</td>';
+ $output .= '<div class="LC_grid_cell" role="grid_cell">'.
+ $codetitles->[$i].'<br />'."\n".
+ '<select name="'.$standardnames->[$i].
+ '" onchange="courseSet('."'$$codetitles[$i]'".')">'."\n".
+ '<option value="-1"><-Pick '.$$codetitles[$i-1].'</option>'."\n".
+ '</select>'."\n".
+ '</div>';
}
- $output .= '</tr></table><br />';
+ $output .= '</div></div><br />';
}
}
$output .=
@@ -2733,7 +2742,7 @@
my ($types,$title,$css_class) = @_;
my $output;
if (defined($title)) {
- $output = &row_title($title,$css_class,'LC_pick_box_select');
+ $output = &row_title('<label for="types">'.$title.'</label>',$css_class,'LC_pick_box_select');
}
$output .= qq|
<select name="types" id="types" multiple="multiple">\n|;
@@ -2767,9 +2776,9 @@
$size = 15;
}
$output .= &Apache::loncommon::start_data_table_row().
- '<td> '.$$authtypes{$auth}.'</td>'.
+ '<td> <label for="'.$auth.'">'.$$authtypes{$auth}.'</label></td>'.
'<td align="right">'.$userentry.
- '<input type="text" name="'.$auth.'" size="'.$size.'" /></td>'.
+ '<input type="text" name="'.$auth.'" id="'.$auth.'" size="'.$size.'" /></td>'.
&Apache::loncommon::end_data_table_row();
}
$output .= &Apache::loncommon::end_data_table();
More information about the LON-CAPA-cvs
mailing list