[LON-CAPA-cvs] cvs: loncom /interface lonwishlist.pm lonwishlistdisplay.pm
raeburn
raeburn at source.lon-capa.org
Sat Dec 27 00:59:46 EST 2025
raeburn Sat Dec 27 05:59:46 2025 EDT
Modified files:
/loncom/interface lonwishlist.pm lonwishlistdisplay.pm
Log:
- WCAG 2 compliance
- Support "Skip to main content" when tabbing in page.
- Include labels for form elements
- Header for each column in a data table by using <th></th> for screen
reader.
-------------- next part --------------
Index: loncom/interface/lonwishlist.pm
diff -u loncom/interface/lonwishlist.pm:1.28 loncom/interface/lonwishlist.pm:1.29
--- loncom/interface/lonwishlist.pm:1.28 Wed Dec 24 18:36:07 2025
+++ loncom/interface/lonwishlist.pm Sat Dec 27 05:59:46 2025
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Utility-routines for wishlist
#
-# $Id: lonwishlist.pm,v 1.28 2025/12/24 18:36:07 raeburn Exp $
+# $Id: lonwishlist.pm,v 1.29 2025/12/27 05:59:46 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -1114,6 +1114,12 @@
foreach my $n (@$nodes) {
my $index = $n->value()->nindex();
+ my $labeltext;
+ if ($n->value()->path() eq '') {
+ $labeltext = &mt('Select [_1] as a folder to which action will apply',$n->value()->title());
+ } else {
+ $labeltext = &mt('Select [_1] as a stored link to which action will apply',$n->value()->title());
+ }
# start row, use data_table routines to set class to LC_even or LC_odd automatically. this row contains a checkbox, the title and the note-icon.
# only display the top level entries on load
@@ -1123,7 +1129,7 @@
# checkboxes
$wishlistHTMLview .= '<td><input type="checkbox" name="mark" id="check'.$index.'" value="'.$index.'" '.
- 'onclick="selectAction('."'row".$index."'".')" /></td>';
+ 'onclick="selectAction('."'row".$index."'".')" aria-label="'.$labeltext.'" /></td>';
# entry is a folder
if ($n->value()->path() eq '') {
@@ -1149,6 +1155,13 @@
$noteIMG = 'anot2.png';
}
+ my $notelabel;
+ if ($n->value()->path() eq '') {
+ $notelabel = &mt('Add or modify note for folder [_1]',$n->value()->title());
+ } else {
+ $notelabel = &mt('Add or modify note for stored link [_1]',$n->value()->title());
+ }
+
$wishlistHTMLview .= '<td style="padding-left:10px;"><a href="javascript:;" onclick="setDisplayNote('."'note".$index."'".')">'.
'<img id="noteImg'.$index.'" src="/res/adm/pages/'.$noteIMG.'" alt="'.&mt('Note').'" title="'.&mt('Note').'" '.
' class="LC_icon"/></a></td>';
@@ -1159,7 +1172,7 @@
$wishlistHTMLview .= &Apache::loncommon::continue_data_table_row('LC_hidden','note'.$index).
'<td></td><td>'.
'<textarea id="noteText'.$index.'" cols="25" rows="3" style="width:100%" '.
- 'name="newnote" >'.
+ 'name="newnote" aria-label="'.$notelabel.'">'.
$n->value()->note().'</textarea></td><td></td>';
$wishlistHTMLview .= &Apache::loncommon::end_data_table_row();
@@ -1183,6 +1196,18 @@
foreach my $n (@$nodes) {
my $index = $n->value()->nindex();
+ my $actionlabel = &mt('select [_1] as item to move or delete',$n->value()->title(),$index);
+ my $titlelabel = &mt('modify title for item currently titled: [_1]',$n->value()->title());
+ my $pathlabel = &mt('modify url for item with current url: [_1]',$n->value()->path());
+ my $notelabel = &mt('modify note for item currently titled: [_1]',$n->value()->title());
+ my $parent;
+ if ($n->parent()->value() eq 'root') {
+ $parent = &mt('Top level');
+ } else {
+ $parent = $n->parent()->value();
+ }
+ my $orderlabel = &mt('change order for [_1], currently item #[_2] in [_3] folder',
+ $n->value()->title(),$curNode,$parent);
# start row, use data_table routines to set class to LC_even or LC_odd automatically.
# this rows contains a checkbox, a select-field for sorting entries, the title in an input-field and the note-icon.
@@ -1192,7 +1217,7 @@
# checkboxes
$wishlistHTMLedit .= '<td><input type="checkbox" name="mark" id="check'.$index.'" value="'.$index.'" '.
- 'onclick="selectAction('."'row".$index."'".')" /></td>';
+ 'onclick="selectAction('."'row".$index."'".')" aria-label="'.$actionlabel.'" /></td>';
# option-tags for sorting entries. we need the numbers from 1 to n with n being the number of entries on the same level as the current entry.
# set the number for the current entry into brackets
@@ -1209,24 +1234,25 @@
# entry is a folder
if ($n->value()->path() eq '') {
- $wishlistHTMLedit .= '<td><select class="LC_hidden" name="sel" id="sel'.$index.'" onchange="submitSelect();">'.
+ $wishlistHTMLedit .= '<td><select class="LC_hidden" name="sel" id="sel'.$index.
+ '" onchange="submitSelect();" aria-label="'.$orderlabel.'">'.
$options.'</select></td>'.
'<td id="padd'.$index.'" style="padding-left:'.(($indent_edit-$indentConst)<0?0:($indent_edit-$indentConst)).'px;">'.
'<a href="javascript:;" onclick="folderAction('."'row".$index."'".')" style="vertical-align:top" >'.
'<img src="/adm/lonIcons/arrow.closed.gif" id="img'.$index.'" alt = "" class="LC_icon"/>'.
'<img src="/adm/lonIcons/navmap.folder.closed.gif" id="imgFolder'.$index.'" alt="folder"/></a>'.
- '<input type="text" name="newtitle" value="'.$n->value()->title().'" alt = "'.$n->value()->title().'" />'.
+ '<input type="text" name="newtitle" value="'.$n->value()->title().'" alt = "'.$n->value()->title().'" aria-label="'.$titlelabel.'" />'.
'</td><td></td>';
}
# entry is a link
else {
- $wishlistHTMLedit .= '<td><select class="LC_hidden" name="sel" id="sel'.$index.'" onchange="submitSelect();">'.
+ $wishlistHTMLedit .= '<td><select class="LC_hidden" name="sel" id="sel'.$index.'" onchange="submitSelect();" aria-label="'.$orderlabel.'">'.
$options.'</select></td>'.
'<td id="padd'.$index.'" style="padding-left:'.(($indent_edit-$indentConst)<=0?$indentConst:$indent_edit).'px;">'.
'<img src="/res/adm/pages/wishlist-link.png" id="img'.$index.'" alt="link"/>'.
- '<input type="text" name="newtitle" value="'.$n->value()->title().'" alt = "'.$n->value()->title().'" /></td>'.
- '<td><input type="text" name="newpath" value="'.$n->value()->path().'" alt = "'.$n->value()->path().'" /></td>';
+ '<input type="text" name="newtitle" value="'.$n->value()->title().'" alt = "'.$n->value()->title().'" aria-label="'.$titlelabel.'" /></td>'.
+ '<td><input type="text" name="newpath" value="'.$n->value()->path().'" alt = "'.$n->value()->path().'" aria-label="'.$pathlabel.'" /></td>';
}
# note-icon, different icons for an entries with note and those without
@@ -1246,7 +1272,7 @@
$wishlistHTMLedit .= &Apache::loncommon::continue_data_table_row('LC_hidden','note'.$index).
'<td></td><td></td><td colspan="2">'.
'<textarea id="noteText'.$index.'" cols="25" rows="3" style="width:100%" '.
- 'name="newnote">'.
+ 'name="newnote" aria-label="'.$notelabel.'">'.
$n->value()->note().'</textarea></td><td></td>';
$wishlistHTMLedit .= &Apache::loncommon::end_data_table_row();
@@ -1367,6 +1393,13 @@
foreach my $n (@$nodes) {
my $index = $n->value()->nindex();
+ my ($labeltext,$notelabel);
+ if ($n->value()->path() eq '') {
+ $notelabel = &mt("Read-only note for '[_1]' folder",$n->value()->title());
+ } else {
+ $labeltext = &mt("Select '[_1]' stored link for import",$n->value()->title());
+ $notelabel = &mt("Read-only note for '[_1]' stored link",$n->value()->title());
+ }
#
# Determine which resources in stored links may be imported into a course/community.
@@ -1413,7 +1446,7 @@
$image = 'wishlist-link.png';
}
$wishlistHTMLimport .= '<input type="checkbox" name="check" id="check'.$index.'" value="'.$index.'" '.
- $disabled.$onclick.' />'.
+ $disabled.$onclick.' aria-label="'.$labeltext.'" />'.
'<input type="hidden" name="title'.$index.'" value="'.&escape($n->value()->title()).'" />'.
'<input type="hidden" name="filelink'.$index.'" value="'.&escape($n->value()->path()).'" />'.
'<input type="hidden" name="id'.$index.'" />';
@@ -1456,7 +1489,7 @@
$wishlistHTMLimport .= &Apache::loncommon::continue_data_table_row('LC_hidden','note'.$index).
'<td></td><td>'.
'<textarea id="noteText'.$index.'" cols="25" rows="3" style="width:100%" '.
- 'name="newnote" readonly="readonly">'.
+ 'name="newnote" readonly="readonly" aria-label="'.$notelabel.'">'.
$n->value()->note().'</textarea></td><td></td>';
$wishlistHTMLimport .= &Apache::loncommon::end_data_table_row();
@@ -1496,6 +1529,7 @@
'onunload' => 'javascript:window.name = '."'$windowname'"}});
my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Stored Links','Wishlist');
+ my $landmark = '<div class="LC_landmark" role="main" id="LC_main_content">'."\n";
# get javascript-code for wishlist-interactions
my $js = &JSforWishlist();
@@ -1570,8 +1604,8 @@
my $subbox = &Apache::loncommon::head_subbox($functions);
# start form
- my $inner .= '<form name="list" action ="/adm/wishlist" method="post">'.
- '<input type="hidden" id="action" name="action" value="" />';
+ my $inner = '<form name="list" action ="/adm/wishlist" method="post">'.
+ '<input type="hidden" id="action" name="action" value="" />';
# only display subbox in view- or edit-mode
if ($mode eq 'view' || $mode eq 'edit') {
@@ -1583,6 +1617,13 @@
&wishlistEdit(\@childrenRt);
if ($wishlistHTMLedit ne '') {
$inner .= &Apache::loncommon::start_data_table("LC_tableOfContent");
+ $inner .= &Apache::loncommon::start_data_table_header_row('LC_visually_hidden').
+ '<th>'.&mt('select for action').'</th>'.
+ '<th>'.&mt('set item order').'</th>'.
+ '<th>'.&mt('title of link or folder').'</th>'.
+ '<th>'.&mt('link url').'</th>'.
+ '<th>'.&mt('access to notes').'</th>'.
+ &Apache::loncommon::end_data_table_row()."\n";
$inner .= $wishlistHTMLedit;
$inner .= &Apache::loncommon::end_data_table();
}
@@ -1594,7 +1635,13 @@
elsif ($mode eq 'view') {
&wishlistView(\@childrenRt);
if ($wishlistHTMLview ne '') {
- $inner .= '<table class="LC_data_table LC_tableOfContent">'.$wishlistHTMLview.'</table>';
+ $inner .= '<table class="LC_data_table LC_tableOfContent">'.
+ &Apache::loncommon::start_data_table_header_row('LC_visually_hidden').
+ '<th>'.&mt('select for action').'</th>'.
+ '<th>'.&mt('title of link or folder').'</th>'.
+ '<th>'.&mt('access to notes').'</th>'.
+ &Apache::loncommon::end_data_table_row()."\n".
+ $wishlistHTMLview.'</table>';
}
else {
$inner .= '<span class="LC_info">'.&mt("Your Stored Links list is currently empty.").'</span>';
@@ -1629,10 +1676,10 @@
$inner .= '</form>';
# end_page
- my $endPage = &Apache::loncommon::end_page();
+ my $endPage = '</div>'.&Apache::loncommon::end_page();
# put all page-elements together
- my $page = $startPage.$breadcrumbs.$js.$inner.$endPage;
+ my $page = $startPage.$breadcrumbs.$js.$landmark.$inner.$endPage;
return $page;
}
@@ -1662,9 +1709,11 @@
my $startPageWishlistlink =
&Apache::loncommon::start_page('Save to Stored Links',undef,
{'only_body' => 1,
- 'bgcolor' => '#FFFFFF',});
+ 'bgcolor' => '#FFFFFF',})
+ .'<div class="LC_landmark" role="main" id="LC_main_content">'."\n";
my $warningLink = &mt('You must insert a title!');
+ my $labeltext = &mt('Folder where new link will be saved');
my $warningLinkNotAllowed1 =
&mt('You can only insert links to LON-CAPA resources from the resource-pool'.
' or to external websites.'.
@@ -1673,7 +1722,7 @@
&js_escape(\$warningLink);
&js_escape(\$warningLinkNotAllowed1);
- my $inPageWishlistlink1 = '<h1>'.&mt('Save to Stored Links').'</h1>';
+ my $inPageWishlistlink1 = '<h1 class="LC_heading_1">'.&mt('Save to Stored Links').'</h1>';
# If no title is delivered, 'New Link' is called up from the wishlist-interface, so after
# submitting the window should close instead of offering a link to wishlist (like it should do
# if we call 'Set New Link' from within a browsed ressource)
@@ -1686,32 +1735,32 @@
'onsubmit="return newlinksubmit();" >';
}
$inPageWishlistlink1 .= &Apache::lonhtmlcommon::start_pick_box().
- &Apache::lonhtmlcommon::row_title(&mt('Link Title'));
+ &Apache::lonhtmlcommon::row_title('<label for="title">'.&mt('Link Title').'</label>');
my $inPageWishlistlink2 = &Apache::lonhtmlcommon::row_closure().
- &Apache::lonhtmlcommon::row_title(&mt('Path'));
+ &Apache::lonhtmlcommon::row_title('<label for="path">'.&mt('Path').'</label>');
my $inPageWishlistlink3 = &Apache::lonhtmlcommon::row_closure().
- &Apache::lonhtmlcommon::row_title(&mt('Note')).
- '<textarea name="note" rows="3" cols="35" style="width:100%"></textarea>'.
+ &Apache::lonhtmlcommon::row_title('<label for="note">'.&mt('Note').'</label>').
+ '<textarea name="note" id="note" rows="3" cols="35" style="width:100%"></textarea>'.
&Apache::lonhtmlcommon::row_closure(1).
&Apache::lonhtmlcommon::end_pick_box().
'<br/><br/>'.
'<input type="submit" value="'.&mt('Save in').'" />'.
- '<select name="folders">'.
+ '<select name="folders" aria-label="'.$labeltext.'">'.
$options.
'</select>'.
'<input type="button" value="'.&mt('Cancel').'" onclick="javascript:window.close();" />'.
'</form>';
$options = '';
- my $endPageWishlistlink = &Apache::loncommon::end_page();
+ my $endPageWishlistlink = '</div>'.&Apache::loncommon::end_page();
my $popUp = $startPageWishlistlink.
$inPageWishlistlink1.
- '<input type="text" name="title" size="45" value="" />'.
+ '<input type="text" name="title" id="title" size="45" value="" />'.
$inPageWishlistlink2.
- '<input type="text" name="path" size="45" value="" />'.
+ '<input type="text" name="path" id="path" size="45" value="" />'.
$inPageWishlistlink3;
# JavaScript-function to set title and path of ressource automatically
@@ -1772,30 +1821,32 @@
my $startPageWishlistfolder =
&Apache::loncommon::start_page('New Folder',undef,
{'only_body' => 1,
- 'bgcolor' => '#FFFFFF',});
+ 'bgcolor' => '#FFFFFF',})
+ .'<div class="LC_landmark" role="main" id="LC_main_content">'."\n";
my $warningFolder = &mt('You must insert a title!');
+ my $labeltext = &mt('Folder in which new (sub)folder will be saved');
&js_escape(\$warningFolder);
- my $inPageNewFolder = '<h1>'.&mt('New Folder').'</h1>'.
+ my $inPageNewFolder = '<h1 class="LC_heading_1">'.&mt('New Folder').'</h1>'.
'<form method="post" name="newfolder" action="/adm/wishlist" target="wishlist" '.
'onsubmit="return newfoldersubmit();" >'.
&Apache::lonhtmlcommon::start_pick_box().
- &Apache::lonhtmlcommon::row_title(&mt('Folder title')).
- '<input type="text" name="title" size="45" value="" /><br />'.
+ &Apache::lonhtmlcommon::row_title('<label for="foldertitle">'.&mt('Folder title').'</label>').
+ '<input type="text" name="title" id="foldertitle" size="45" value="" /><br />'.
&Apache::lonhtmlcommon::row_closure().
- &Apache::lonhtmlcommon::row_title(&mt('Note')).
- '<textarea name="note" rows="3" cols="35" style="width:100%"></textarea><br />'.
+ &Apache::lonhtmlcommon::row_title('<label for="foldernote">'.&mt('Note').'</label>').
+ '<textarea name="note" id="foldernote" rows="3" cols="35" style="width:100%"></textarea><br />'.
&Apache::lonhtmlcommon::row_closure(1).
&Apache::lonhtmlcommon::end_pick_box().
'<br/><br/>'.
'<input type="submit" value="'.&mt('Save in').'" />'.
- '<select name="folders">'.
+ '<select name="folders" aria-label="'.$labeltext.'">'.
$options.
'</select>'.
'<input type="button" value="'.&mt('Cancel').'" onclick="javascript:window.close();" />'.
'</form>';
- my $endPageWishlistfolder = &Apache::loncommon::end_page();
+ my $endPageWishlistfolder = '</div>'.&Apache::loncommon::end_page();
my $popUp = $startPageWishlistfolder.
$inPageNewFolder;
@@ -1826,7 +1877,8 @@
my $output =
&Apache::loncommon::start_page($title,undef,
{'only_body' => 1})
- .'<h1>'.&mt($title).'</h1>';
+ .'<div class="LC_landmark" role="main" id="LC_main_content">'."\n"
+ .'<h1 class="LC_heading_1">'.&mt($title).'</h1>';
# confirm success and offer link to wishlist
$output .=
@@ -1839,7 +1891,7 @@
]);
# end_page
- $output .= &Apache::loncommon::end_page();
+ $output .= '</div>'.&Apache::loncommon::end_page();
return $output;
}
@@ -1860,7 +1912,8 @@
my $js = &JSforWishlist();
$js .= &JSforImport($rat);
- my $inner = '<h1>'.&mt('Import Resources from Stored Links').'</h1>';
+ my $landmark = '<div class="LC_landmark" role="main" id="LC_main_content">'."\n";
+ my $inner = '<h1 class="LC_heading_1">'.&mt('Import Resources from Stored Links').'</h1>';
if (!$rat) {
$inner .=
'<ul>'.
@@ -1904,7 +1957,13 @@
my $numskipped = 0;
&wishlistImport(\@childrenRt,\$numskipped);
if ($wishlistHTMLimport ne '') {
- $inner .= '<table class="LC_data_table LC_tableOfContent">'.$wishlistHTMLimport.'</table>';
+ $inner .= '<table class="LC_data_table LC_tableOfContent">'.
+ &Apache::loncommon::start_data_table_header_row('LC_visually_hidden').
+ '<th>'.&mt('select link for import').'</th>'.
+ '<th>'.&mt('title of link or folder').'</th>'.
+ '<th>'.&mt('access to notes').'</th>'.
+ &Apache::loncommon::end_data_table_row()."\n".
+ $wishlistHTMLimport.'</table>';
}
else {
$inner .= '<span class="LC_info">'.&mt("Your Stored Links list is currently empty.").'</span>';
@@ -1917,10 +1976,10 @@
$inner .= '</form>';
# end_page
- my $endPage = &Apache::loncommon::end_page();
+ my $endPage = '</div>'.&Apache::loncommon::end_page();
# put all page-elements together
- my $page = $startPage.$js.$inner.$endPage;
+ my $page = $startPage.$js.$landmark.$inner.$endPage;
return $page;
}
Index: loncom/interface/lonwishlistdisplay.pm
diff -u loncom/interface/lonwishlistdisplay.pm:1.7 loncom/interface/lonwishlistdisplay.pm:1.8
--- loncom/interface/lonwishlistdisplay.pm:1.7 Fri Dec 24 00:48:30 2021
+++ loncom/interface/lonwishlistdisplay.pm Sat Dec 27 05:59:46 2025
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Routines to display the wishlist (handler)
#
-# $Id: lonwishlistdisplay.pm,v 1.7 2021/12/24 00:48:30 raeburn Exp $
+# $Id: lonwishlistdisplay.pm,v 1.8 2025/12/27 05:59:46 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -74,8 +74,9 @@
text => 'Stored Links'});
my $startPage = &Apache::loncommon::start_page('Stored Links');
my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Stored Links','Wishlist');
- my $endpage = &Apache::loncommon::end_page();
- $r->print($startPage.$breadcrumbs.$blocktext);
+ my $landmark = '<div class="LC_landmark" role="main" id="LC_main_content">'."\n";
+ my $endpage = '</div>'.&Apache::loncommon::end_page();
+ $r->print($startPage.$breadcrumbs.$landmark.$blocktext.$endpage);
return OK;
}
More information about the LON-CAPA-cvs
mailing list