[LON-CAPA-cvs] cvs: loncom /interface portfolio.pm
raeburn
raeburn at source.lon-capa.org
Sun Dec 14 21:17:10 EST 2025
raeburn Mon Dec 15 02:17:10 2025 EDT
Modified files:
/loncom/interface portfolio.pm
Log:
- WCAG 2 compliance.
-------------- next part --------------
Index: loncom/interface/portfolio.pm
diff -u loncom/interface/portfolio.pm:1.274 loncom/interface/portfolio.pm:1.275
--- loncom/interface/portfolio.pm:1.274 Mon Dec 15 02:15:29 2025
+++ loncom/interface/portfolio.pm Mon Dec 15 02:17:10 2025
@@ -1,7 +1,7 @@
# The LearningOnline Network
# portfolio browser
#
-# $Id: portfolio.pm,v 1.274 2025/12/15 02:15:29 raeburn Exp $
+# $Id: portfolio.pm,v 1.275 2025/12/15 02:17:10 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -93,6 +93,8 @@
'createdir' => 'Create Subdirectory',
'createdir_label' => 'Create subdirectory in current directory',
'parse' => 'Upload embedded images/multimedia/css/linked files if HTML file',
+ 'subdir' => 'Subdirectory name',
+ 'file' => 'Choose a file',
);
my $escuri = &HTML::Entities::encode($r->uri,'&<>"');
my $help_fileupload = &Apache::loncommon::help_open_topic('Portfolio AddFiles');
@@ -121,7 +123,7 @@
.'<fieldset>'
.'<legend>'.$lt{'upload_label'}.'</legend>'
.$groupitem
- .'<input name="uploaddoc" type="file" class="LC_flUpload" />'
+ .'<input name="uploaddoc" type="file" class="LC_flUpload" aria-label="'.$lt{'file'}.'" />'
.'<input type="hidden" id="LC_free_space" value="'.$free_space.'" />'
.'<input type="hidden" name="currentpath" value="'.$current_path.'" />'
.'<input type="hidden" name="action" value="'.$env{"form.action"}.'" />'
@@ -140,7 +142,7 @@
.'<form method="post" action="'.$escuri.'">'
.'<fieldset>'
.'<legend>'.$lt{'createdir_label'}.'</legend>'
- .'<input name="newdir" type="text" />'.$groupitem
+ .'<input name="newdir" type="text" aria-label="'.$lt{'subdir'}.'" />'.$groupitem
.'<input type="hidden" name="currentpath" value="'.$current_path.'" />'
.'<input type="hidden" name="action" value="'.$env{"form.action"}.'" />'
.'<input type="hidden" name="symb" value="'.$env{"form.symb"}.'" />'
@@ -186,7 +188,8 @@
$r->print('<br /><form method="post" action="'.$url.'?mode='.$env{"form.mode"}.'&fieldname='.$env{"form.fieldname"}.'&symb='.$env{'form.symb'}.&group_args());
$r->print('">'.
&Apache::lonhtmlcommon::select_recent($namespace,'currentpath',
- 'this.form.submit();'));
+ 'this.form.submit();',
+ &mt('Select recently visited directory')));
$r->print("</form>");
}
@@ -250,7 +253,7 @@
$r->print('<td>'.$size.'</td>');
$r->print('<td>'.&Apache::lonlocal::locallocaltime($mtime).'</td>');
if ($select_mode ne 'true') {
- $r->print('<td class="'.$css_class.'"> </td>'); # Display status
+ $r->print('<td class="'.$css_class.'" aria-hidden="true"> </td>'); # Display status
$r->print('<td><span class="LC_nobreak">'
.&mt($curr_access).' '
);
@@ -260,7 +263,7 @@
);
$r->print(&make_anchor($url, \%anchor_fields, $access_admin_text).'</span></td>');
} else {
- $r->print('<td class="'.$css_class.'"> </td>'); # Display status
+ $r->print('<td class="'.$css_class.'" aria-hidden="true"> </td>'); # Display status
}
$r->print(&Apache::loncommon::end_data_table_row().$/);
}
@@ -297,12 +300,12 @@
$r->print(&Apache::loncommon::start_data_table()
.&Apache::loncommon::start_data_table_header_row()
.'<th>'.&mt('Select').'</th>'
- .'<th> </th>'
- .'<th> </th>'
+ .'<th><span class="LC_visually_hidden">'.&mt('File type').'</span></th>'
+ .'<th><span class="LC_visually_hidden">'.&mt('Multiple versions?').'</span></th>'
.'<th>'.&mt('Name').'</th>'
.'<th>'.&mt('Size').'</th>'
.'<th>'.&mt('Last Modified').'</th>'
- .'<th> </th>'
+ .'<th aria-hidden="true">'.&mt('Tag').'</th>'
.&Apache::loncommon::end_data_table_header_row()
);
} else {
@@ -329,12 +332,12 @@
$r->print(&Apache::loncommon::start_data_table()
.&Apache::loncommon::start_data_table_header_row()
.'<th colspan="2">'.&mt('Actions'). &Apache::loncommon::help_open_topic('Portfolio FileAction').'</th>'
- .'<th> </th>'
- .'<th> </th>'
+ .'<th><span class="LC_visually_hidden">'.&mt('File type').'</span></th>'
+ .'<th><span class="LC_visually_hidden">'.&mt('Multiple versions?').'</span></th>'
.'<th>'.&mt('Name').&Apache::loncommon::help_open_topic('Portfolio OpenFile').'</th>'
.'<th>'.&mt('Size').'</th>'
.'<th>'.&mt('Last Modified').'</th>'
- .'<th> </th>'
+ .'<th aria-hidden="true">'.&mt('Tag').'</th>'
.'<th>'.&mt('Current Access Status').$acl_helplink.'</th>'
.&Apache::loncommon::end_data_table_header_row());
}
@@ -461,7 +464,7 @@
if ($$checked_files{$filename} eq 'selected') {
$line.=' checked="checked" ';
}
- $line.=' /></td>';
+ $line.=' aria-label="'.&mt('Include file for assignment').'" /></td>';
} else {
$line = '<td> </td>';
$zerobyte ++;
@@ -480,10 +483,10 @@
$line .= '<td>';
}
if ($can_delete) {
- $line .= '<input type="checkbox" name="selectfile" value="'.$filename.'" />';
+ $line .= '<input type="checkbox" name="selectfile" value="'.$filename.'" aria-label="'.&mt('Select file for deletion').'" />';
}
if ($can_modify) {
- my $cat='<img class="LC_icon" alt="'.&mt('Metadata').'" title="'.&mt('Metadata').'" src="'.&Apache::loncommon::lonhttpdurl('/res/adm/pages/catalog.png').'" />';
+ my $cat='<img class="LC_icon" alt="'.&mt('Metadata').'" title="'.&mt('Set/view metadata').'" src="'.&Apache::loncommon::lonhttpdurl('/res/adm/pages/catalog.png').'" />';
my %anchor_fields = (
'rename' => $filename,
currentpath => $current_path
@@ -600,15 +603,18 @@
'cancel' => &mt('Cancel'),
};
}
- $r->print('<p><input type="submit" value="'.$button_text->{'continue'}.'" />');
+ $r->print('<div><p><input type="submit" value="'.$button_text->{'continue'}.'" />');
$r->print(&group_form_data().'</p></form>');
- $r->print('<form action="'.$url.'" method="post">
- <p>
- <input type="hidden" name="currentpath" value="'.
- $env{'form.currentpath'}.'" />'.
- &group_form_data());
- $r->print("\n".' <input type="submit" value="'.$button_text->{'cancel'}.'" />
- </p></form>');
+ if ($button_text->{'cancel'} ne '') {
+ $r->print('<form action="'.$url.'" method="post">
+ <p>
+ <input type="hidden" name="currentpath" value="'.
+ $env{'form.currentpath'}.'" />'.
+ &group_form_data());
+ $r->print("\n".' <input type="submit" value="'.$button_text->{'cancel'}.'" />
+ </p></form>');
+ }
+ $r->print('</div>');
}
sub display_file {
@@ -916,7 +922,7 @@
my $uhome = &Apache::lonnet::homeserver($uname,$udom);
my $prefix = &Apache::lonnet::url_prefix($r,$udom,$uhome,'web');
$header =
- '<h2>'
+ '<h2 class="LC_heading_2">'
.&mt('Allowing others to retrieve file: [_1]'
,'<span class="LC_filename">'
.$port_path.$env{'form.currentpath'}.$env{'form.access'}
@@ -938,22 +944,17 @@
$info .= &mt("Users with course editing rights may add a 'Group Portfolio' item using the Course Editor (Collaboration tab), to provide access to viewable group portfolio files.").'<br />';
}
} else {
- $header = '<h3>'.&mt('Conditional access controls for file: [_1]',$port_path.$env{'form.currentpath'}.$env{'form.access'}).'</h3>'.
+ $header = '<h2 class="LC_heading_2">'.&mt('Conditional access controls for file: [_1]',$port_path.$env{'form.currentpath'}.$env{'form.access'}).'</h2>'.
&explain_conditionals().'<br />';
}
if ($can_setacl) {
&open_form($r,$url);
$r->print($header.$info);
- $r->print('<br />'.&Apache::loncommon::help_open_topic('Portfolio ShareFile SetAccess', &mt('Help on setting up share access')));
+ $r->print('<br /><div>'.&Apache::loncommon::help_open_topic('Portfolio ShareFile SetAccess', &mt('Help on setting up share access')));
$r->print(&Apache::loncommon::help_open_topic('Portfolio ShareFile ChangeSetting', &mt('Help on changing settings')));
- $r->print(&Apache::loncommon::help_open_topic('Portfolio ShareFile StopAccess', &mt('Help on removing share access')));
+ $r->print(&Apache::loncommon::help_open_topic('Portfolio ShareFile StopAccess', &mt('Help on removing share access')).'</div>');
&access_setting_table($r,$url,$file_name,$access_controls{$file_name},
$action);
- my $button_text = {
- 'continue' => &mt('Proceed'),
- 'cancel' => &mt('Return to directory'),
- };
- &close_form($r,$url,$button_text);
} elsif ($can_viewacl) {
$r->print($header);
if ($aclcount) {
@@ -1263,8 +1264,8 @@
time => {
start => $start,
end => $end
- },
- };
+ },
+ };
if ($scope eq 'guest') {
$record->{'password'} = $env{'form.password'};
@@ -1291,7 +1292,6 @@
if ($next_id ne '') {
push(@role_ids,$next_id);
}
-
foreach my $id (@role_ids) {
my (@roles, at accesses, at sections, at groups);
if (($next_id ne '') && ($id == $next_id) && ($chg eq 'update')) {
@@ -1401,22 +1401,21 @@
}
$acl_count{$scope} ++;
}
- $r->print('<table border="0"><tr><td valign="top">');
if ($action eq 'chgaccess') {
&standard_settings($r,$now,$then,$url,$filename,\%acl_count,\%start,
\%end,$public,$publicnum,$publictext,$guest,$guestnum,
$guesttext,$access_controls,%conditionals);
} else {
- &condition_setting($r,$access_controls,$now,$then,\%acl_count,
+ &condition_setting($r,$url,$access_controls,$now,$then,\%acl_count,
\@domains,\@users,\@courses,\@ips);
}
- $r->print('</td></tr></table>');
}
sub standard_settings {
my ($r,$now,$then,$url,$filename,$acl_count,$start,$end,$public,$publicnum,
$publictext,$guest,$guestnum,$guesttext,$access_controls,%conditionals)=@_;
- $r->print('<h3>'.&mt('Public access: [_1]',&mt($publictext)).'</h3>');
+ $r->print('<div class="LC_floatleft" style="vertical-align: top;">'.
+ '<h3 class="LC_heading_3">'.&mt('Public access: [_1]',&mt($publictext)).'</h3>');
$r->print(&Apache::loncommon::start_data_table());
$r->print(&Apache::loncommon::start_data_table_header_row());
$r->print('<th>'.&mt('Action').'</th><th>'.&mt('Dates available').'</th>');
@@ -1431,8 +1430,8 @@
}
$r->print(&Apache::loncommon::end_data_table_row());
$r->print(&Apache::loncommon::end_data_table());
- $r->print('</td><td width="40"> </td><td valign="top">');
- $r->print('<h3>'.&mt('Passphrase-protected access: [_1]',&mt($guesttext)).'</h3>');
+ $r->print('</div><div class="LC_floatleft" style="vertical-align: top;">');
+ $r->print('<h3 class="LC_heading_3">'.&mt('Passphrase-protected access: [_1]',&mt($guesttext)).'</h3>');
$r->print(&Apache::loncommon::start_data_table());
$r->print(&Apache::loncommon::start_data_table_header_row());
$r->print('<th>'.&mt('Action').'</th><th>'.&mt('Dates available').
@@ -1449,11 +1448,15 @@
&dateboxes('1',$now,$then).'</td>');
}
$r->print('<td><input type="text" size="15" name="password" value="'.
- $passwd.'" /></td>');
+ $passwd.'" aria-label="'.&mt('passphrase').'" /></td>');
$r->print(&Apache::loncommon::end_data_table_row());
$r->print(&Apache::loncommon::end_data_table());
- $r->print('</td></tr><tr><td colspan="3"> </td></tr>'.
- '<tr><td colspan="3" valign="top">');
+ $r->print('</div>'.
+ '<div style="padding:0;clear:both;margin:0;border:0"></div>'."\n");
+ my $button_text = {
+ 'continue' => &mt('Proceed'),
+ };
+ &close_form($r,$url,$button_text);
my $numconditionals = 0;
my $conditionstext;
my %cond_status;
@@ -1478,7 +1481,9 @@
'action' => 'chgconditions',
'currentpath' => $env{'form.currentpath'},
);
- $r->print('<h3>'.&mt('Conditional access: [_1]',&mt($conditionstext)).'</h3>');
+ $r->print('<div style="padding:0;clear:both;margin:0;border:0"></div>'.
+ '<div class="LC_floatleft" style="vertical-align: top;">'.
+ '<h3 class="LC_heading_3">'.&mt('Conditional access: [_1]',&mt($conditionstext)).'</h3>');
if ($numconditionals > 0) {
my $count = 1;
my $chg = 'none';
@@ -1493,19 +1498,25 @@
} else {
$r->print(&make_anchor($url,\%anchor_fields,&mt('Add conditional access')).' '.&mt("based on domain, username, course/community affiliation or user's IP address."));
}
+ $r->print('</div>'.
+ '<div style="padding:0;clear:both;margin:0;border:0"></div>'."\n");
}
sub condition_setting {
- my ($r,$access_controls,$now,$then,$acl_count,$domains,$users,$courses,$ips) = @_;
- $r->print('<tr><td valign="top">');
+ my ($r,$url,$access_controls,$now,$then,$acl_count,$domains,$users,$courses,$ips) = @_;
+ $r->print('<div class="LC_floatleft" style="vertical-align: top;">');
&access_element($r,'domains',$acl_count,$domains,$access_controls,$now,$then);
- $r->print('</td><td> </td><td valign="top">');
- &access_element($r,'users',$acl_count,$users,$access_controls,$now,$then);
- $r->print('</td></tr><tr><td colspan="3"></td></tr><tr><td valign="top">');
+ $r->print('<p />');
&access_element($r,'course',$acl_count,$courses,$access_controls,$now,$then);
- $r->print('</td><td> </td><td valign="top">');
+ $r->print('</div><div class="LC_floatleft" style="vertical-align: top;">');
+ &access_element($r,'users',$acl_count,$users,$access_controls,$now,$then);
+ $r->print('<p />');
&access_element($r,'userip',$acl_count,$ips,$access_controls,$now,$then);
- $r->print('</td></tr></table>');
+ $r->print('</div><div style="padding:0;clear:both;margin:0;border:0"></div>');
+ my $button_text = {
+ 'continue' => &mt('Proceed'),
+ };
+ &close_form($r,$url,$button_text);
}
sub acl_status {
@@ -1527,7 +1538,7 @@
course => 'Course/Community',
userip => 'IP',
);
- $r->print('<h3>'.&mt($typetext{$type}.'-based conditional access:').' ');
+ $r->print('<h3 class="LC_heading_3">'.&mt($typetext{$type}.'-based conditional access:').' ');
if ($$acl_count{$type}) {
$r->print(&mt('[quant,_1,condition]',$$acl_count{$type}));
} else {
@@ -1672,7 +1683,8 @@
}
$r->print('<td><input type="hidden" name="crsdom_'.$num.'" value="'.$content->{'domain'}.'" /><input type="hidden" name="crsnum_'.$num.'" value="'.$content->{'number'}.'" />'.$course_description{'description'}.'</td>');
} elsif ($status eq 'new') {
- $r->print('<td>'.&Apache::loncommon::selectcourse_link('portform','crsnum_'.$num,'crsdom_'.$num,'description_'.$num,$num.'_1',undef,$showtype).' <input type="text" name="description_'.$num.'" size="30" /><input type="hidden" name="crsdom_'.$num.'" /><input type="hidden" name="crsnum_'.$num.'" /></td>');
+ my $labeltext = &mt('new');
+ $r->print('<td>'.&Apache::loncommon::selectcourse_link('portform','crsnum_'.$num,'crsdom_'.$num,'description_'.$num,$num.'_1',undef,$showtype).' <input type="text" name="description_'.$num.'" size="30" aria-label="'.$labeltext.'" onfocus="this.blur();opencrsbrowser('."'portform','crsnum_".$num."','crsdom_".$num."','description_".$num."','".$num."_1','','$showtype'".')"; /><input type="hidden" name="crsdom_'.$num.'" /><input type="hidden" name="crsnum_'.$num.'" /></td>');
}
$r->print('<td>'.&dateboxes($num,$start,$end));
my $newrole_id = 1;
@@ -1695,11 +1707,11 @@
}
$r->print('</table>');
}
- $r->print('<br />'.&mt('Add a roles-based condition').
+ $r->print('<br /><label>'.&mt('Add a roles-based condition').
' <input type="checkbox" name="add_role_'.
$num.'" onclick="javascript:setRoleOptions('."'$num',
'$max_id','$content->{'domain'}','$content->{'number'}',
- '$showtype'".')" value="" />');
+ '$showtype'".')" value="" /></label>');
$newrole_id = $max_id;
} else {
$r->print('<input type="hidden" name="add_role_'.$num.'" value="" />');
@@ -1723,7 +1735,8 @@
my ($r,$status,$item,$all_doms,$access_controls,$now,$then) = @_;
my ($num,$scope,$end,$start) = &set_identifiers($status,$item,$now,$then,
'domains');
- my $dom_select = '<select name="dom_'.$num.'" size="4" multiple="multiple">'.
+ my $labeltext = &mt('Domain(s) with conditional access');
+ my $dom_select = '<select name="dom_'.$num.'" size="4" multiple="multiple" aria-label="'.$labeltext.'">'.
' <option value="">'.&mt('Please select').'</option>';
if ($status eq 'old') {
my $content = $$access_controls{$item};
@@ -1755,7 +1768,8 @@
my $content = $$access_controls{$item};
$curr_user_list = &sort_users($content->{'users'});
}
- $r->print('<td>'.&actionbox($status,$num,$scope).'</td><td>'.&mt("Format for users' username:domain information:").'<br /><tt>sparty:msu,illini:uiuc ... etc.</tt><br /><textarea name="users_'.$num.'" cols="30" rows="5">'.$curr_user_list.'</textarea></td><td>'.&dateboxes($num,$start,$end).'</td>');
+ my $labeltext = &mt('User(s) with conditional access');
+ $r->print('<td>'.&actionbox($status,$num,$scope).'</td><td>'.&mt("Format for users' username:domain information:").'<br /><tt>sparty:msu,illini:uiuc ... etc.</tt><br /><textarea name="users_'.$num.'" cols="30" rows="5" aria-label="'.$labeltext.'">'.$curr_user_list.'</textarea></td><td>'.&dateboxes($num,$start,$end).'</td>');
}
sub ips_row {
@@ -1767,11 +1781,12 @@
my $content = $$access_controls{$item};
$curr_ips_list = &sort_ips($content->{'userip'});
}
+ my $labeltext = &mt('IP addresess(s) with conditional access');
$r->print('<td>'.&actionbox($status,$num,$scope).'</td><td>'.&mt('Format for IP controls').'<br />'.
&mt('[_1] or [_2] or [_3] or [_4] or [_5]','<tt>35.8.*</tt>','<tt>35.8.3.[34-56]</tt>',
'<tt>*.msu.edu</tt>','<tt>35.8.3.34</tt>','<tt>somehostname.pa.msu.edu</tt>').'<br />'.
&mt('Use a comma to separate different ranges.').'</br/>'.
- '<textarea name="ips_'.$num.'" cols="30" rows="5">'.$curr_ips_list.'</textarea></td>'.
+ '<textarea name="ips_'.$num.'" cols="30" rows="5" aria-label="'.$labeltext.'">'.$curr_ips_list.'</textarea></td>'.
'<td>'.&dateboxes($num,$start,$end).'</td>');
}
@@ -1787,15 +1802,50 @@
} elsif ($type eq 'userip') {
$showtype = 'IP';
}
+ my $labeltext = &mt('number of '.$showtype.'-based condition(s)');
return
&mt('Add new '.$showtype.'-based condition(s)?')
.' '.&mt('Number to add: ')
- .'<input type="text" name="new'.$type.'" size="3" value="0" />';
+ .'<input type="text" name="new'.$type.'" size="3" value="0" aria-label="'.$labeltext.'" />';
}
sub actionbox {
my ($status,$num,$scope) = @_;
- my $output = '<span class="LC_nobreak"><label>';
+ my $legend;
+ if (($scope eq 'course') || ($scope eq 'domains') ||
+ ($scope eq 'users') || ($scope eq 'userip')) {
+ my $showtype;
+ if ($scope eq 'course') {
+ $showtype = 'course/community';
+ } elsif ($scope eq 'domains') {
+ $showtype = 'domain';
+ } elsif ($scope eq 'users') {
+ $showtype = 'user';
+ } elsif ($scope eq 'userip') {
+ $showtype = 'IP';
+ }
+ if ($status eq 'new') {
+ $legend = &mt('Action for new '.$showtype.'-based condition');
+ } else {
+ $legend = &mt('Action for existing '.$showtype.'-based condition');
+ }
+ } elsif ($scope eq 'public') {
+ if ($status eq 'new') {
+ $legend = &mt('Action for new public access');
+ } else {
+ $legend = &mt('Action for existing public access');
+ }
+ } elsif ($scope eq 'guest') {
+ if ($status eq 'new') {
+ $legend = &mt('Action for new passphrase-protected access');
+ } else {
+ $legend = &mt('Action for existing passphrase-protected access');
+ }
+ }
+ my $output = '<fieldset class="LC_borderless">'
+ .'<legend class="LC_visually_hidden">'.$legend
+ .'</legend>'
+ .'<span class="LC_nobreak"><label>';
if ($status eq 'new') {
my $checkstate;
if ($scope eq 'domains' || $scope eq 'users' || $scope eq 'course' || $scope eq 'userip') {
@@ -1810,7 +1860,7 @@
'<label><input type="checkbox" name="update" value="'.
$num.'" />'.&mt('Update');
}
- $output .= '</label></span><input type="hidden" name="scope_'.$num.'" value="'.$scope.'" />';
+ $output .= '</label></span><input type="hidden" name="scope_'.$num.'" value="'.$scope.'" /></fieldset>';
return $output;
}
@@ -1897,8 +1947,14 @@
'section' => $sections,
'group' => $groups,
);
+ my %lt = &Apache::lonlocal::texthash (
+ 'role' => 'Role(s) with access',
+ 'access' => 'Course status(es) with access',
+ 'section' => 'Section(s) with access',
+ 'group' => 'Group(s) with access',
+ );
foreach my $item ('role','access','section','group') {
- $output .= '<td><select name="'.$item.$longid.'" multiple="multiple" size="4">'."\n";
+ $output .= '<td><select name="'.$item.$longid.'" multiple="multiple" size="4" aria-label="'.$lt{$item}.'">'."\n";
foreach my $entry (@{$allitems{$item}}) {
if ($caller eq 'display') {
if ((@{$$content{'roles'}{$role_id}{$item}} > 0) &&
@@ -1961,13 +2017,14 @@
</script>
END_SCRIPT
$r->print(
- '<p>'
+ '<h1 class="LC_heading_2">'.
+ .&mt('Select roles, sections and groups for role-based access condition').
+ .'</h1>'
+ .'<p>'
.&mt('Select roles, '.lc($type).' status, section(s) and group(s) for users'
.' who will be able to access the portfolio file.')
.'</p>'
- );
- $r->print(
- '<form name="rolepicker" action="/adm/portfolio" method="post">'
+ .'<form name="rolepicker" action="/adm/portfolio" method="post">'
.'<table><tr>'
.'<th>'.&mt('Roles').'</th>'
.'<th>'.&mt("$type status").'</th>'
More information about the LON-CAPA-cvs
mailing list