[LON-CAPA-cvs] cvs: loncom /html/res/adm/pages accessibility-22x22.png /interface lonmenu.pm /node.js/axe lonaxe.pl /publisher loncfile.pm

raeburn raeburn at source.lon-capa.org
Tue Mar 31 19:29:36 EDT 2026


raeburn		Tue Mar 31 23:29:36 2026 EDT

  Added files:                 
    /loncom/html/res/adm/pages	accessibility-22x22.png 

  Modified files:              
    /loncom/publisher	loncfile.pm 
    /loncom/interface	lonmenu.pm 
    /loncom/node.js/axe	lonaxe.pl 
  Log:
  - Accessibility testing using axe-core and puppeteer (node.js).
    - Icon/link to accessibility checker in Functions menu in Authoring Space,
      when listing a directory, or displaying a file of appropriate type, i.e.,
      file extension: .problem, .exam, .quiz, .assess, .survey, .xml, .html, 
      .htm, .xhtml, or .xhtm.
    - For a directory choose which file types should be checked, and if any
      subdirectories should also be checked (recursively).
    - Choose Accessibility level to test: 2.0, 2.1, 2.2 and A, AA, AAA
    - Summary results written to .csv file for download.
    - Details for any violations written to .txt file for download.
  
  
-------------- next part --------------
Index: loncom/publisher/loncfile.pm
diff -u loncom/publisher/loncfile.pm:1.132 loncom/publisher/loncfile.pm:1.133
--- loncom/publisher/loncfile.pm:1.132	Sat Aug  2 20:58:35 2025
+++ loncom/publisher/loncfile.pm	Tue Mar 31 23:29:34 2026
@@ -9,7 +9,7 @@
 #  and displays a page showing the results of the action.
 #
 #
-# $Id: loncfile.pm,v 1.132 2025/08/02 20:58:35 raeburn Exp $
+# $Id: loncfile.pm,v 1.133 2026/03/31 23:29:34 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -1031,6 +1031,202 @@
               '<br />');
 }
 
+sub Accessibility1 {
+    my ($r,$fn) = @_;
+    my $warning = &lock_warning('Checking Accessibility');
+    if ($warning) {
+        $r->print($warning);
+        return;
+    }
+    my @posstypes = qw(problem exam quiz assess survey xml html xhtml htm xhtm);
+    if ((-e $fn) && ((-d $fn) || ($fn =~ /\.(problem|exam|quiz|assess|survey|xml|x?html?)$/))) {
+        $r->print('<input type="hidden" name="accdload" value="" />'."\n".
+                  &Apache::lonhtmlcommon::start_pick_box().
+                  &Apache::lonhtmlcommon::row_title(&mt('Directory')).
+                  &display($fn).
+                  &Apache::lonhtmlcommon::row_closure().
+                  &Apache::lonhtmlcommon::row_title(&mt('Options').
+                  &Apache::loncommon::help_open_topic('Accessibility_Checking_Options')));
+        if (-d $fn) {
+            $r->print('<fieldset><legend>'.&mt('Recurse').'</legend>'.
+                      '<span class="LC_nobreak"><label><input type="checkbox" name="recurse" /> '.
+                      &mt('include subdirectories').'</label></span>'.
+                      '</fieldset>'.
+                      '<fieldset><legend>'.&mt('File types (extensions) to include').(' 'x2).
+                      '<span style="text-decoration:line-through">'.(' 'x5).'</span>'.(' 'x2).
+                      '<input type="button" name="checkall" value="'.&mt('check all').
+                      '" style="height:20px;" onclick="checkAll(document.phaseone.filetype);" />'.
+                      (' 'x2).
+                      '<input type="button" name="uncheckall" value="'.&mt('uncheck all').
+                      '" style="height:20px;" onclick="uncheckAll(document.phaseone.filetype);" /></legend>'.
+                      '<table>');
+            my $rem;
+            my $numinrow = 6;
+            for (my $i=0; $i<@posstypes; $i++) {
+                my $rem = $i%($numinrow);
+                if ($rem == 0) {
+                    if ($i > 0) {
+                        $r->print('</tr>'."\n");
+                    }
+                    $r->print('<tr>'."\n");
+                }
+                $r->print('<td class="LC_left_item">'.
+                          '<span class="LC_nobreak"><label>'.
+                          '<input type="checkbox" name="filetype" '.
+                          'value="'.$posstypes[$i].'" /> '.
+                          $posstypes[$i].'</label></span></td>'."\n");
+            }
+            $rem = scalar(@posstypes)%($numinrow);
+            my $colsleft;
+            if ($rem) {
+                $colsleft = $numinrow - $rem;
+            }
+            if ($colsleft > 1) {
+                $r->print('<td colspan="'.$colsleft.'" class="LC_left_item">'.
+                                ' </td>'."\n");
+            } elsif ($colsleft == 1) {
+                $r->print('<td class="LC_left_item"> </td>'."\n");
+            }
+            $r->print('</tr></table>'."\n".
+                      '</fieldset>');
+        }
+        $r->print('<fieldset class="LC_wcag"><legend>'.&mt('WCAG standard').'</legend>');
+        foreach my $standard ('2.0','2.1','2.2') {
+            my $value = $standard;
+            $value =~ s/\.//;
+            my $checked;
+            if ($standard eq '2.2') {
+                $checked = ' checked="checked"';
+            }
+            $r->print('<span class="LC_nobreak">'.
+                      '<label><input type="radio" name="standard" value="'.$value.'"'.$checked.' />'.
+                      $standard.'</label></span>'.(' 'x2));
+        }
+        $r->print('</fieldset>'."\n".
+                  '<fieldset class="LC_wcag"><legend>'.&mt('Compliance level').'</legend>'.
+                  '<span class="LC_nobreak">');
+        foreach my $level ('A','AA','AAA') {
+            my $checked;
+            if ($level eq 'AA') {
+                $checked = ' checked="checked"';
+            }
+            $r->print('<label><input type="radio" name="compliance" value="'.lc($level).'"'.$checked.' />'.
+                      $level.'</label></span>'.(' 'x2));
+        }
+        $r->print('</fieldset>'."\n".
+                  &Apache::lonhtmlcommon::row_closure(1).
+                  &Apache::lonhtmlcommon::end_pick_box().'<br />'."\n"
+        );
+        &CloseForm1($r, $fn);
+    }
+    return;
+}
+
+sub lock_warning {
+    my ($locktext) = @_;
+    if ($locktext ne '') {
+        my $lockid;
+        my ($numlocks,%locks)=&Apache::lonnet::get_locks();
+        if ($numlocks) {
+            foreach my $id (keys(%locks)) {
+                if ($locks{$id} =~ /^\Q$locktext\E/) {
+                    $lockid = $id;
+                    last;
+                }
+            }
+            if ($lockid) {
+                return '<h2 class="LC_heading_2">'.&mt('Accessibility checking in progress').'</h2>'
+                      .&mt('When an Accessibility check is started a lock set in your session remains in place until completion.')
+                      .'<br />'.&mt('An existing lock in your current session is preventing another check being started.')
+                      .'<p>'.&mt("If the lock should have been removed, but wasn't, you can clear it by attempting to [_1]logout[_2] of LON-CAPA and pushing the 'Override' button.",'<a href="/adm/logout">','</a>').'</p>';
+            }
+        }
+    }
+    return;
+}
+
+sub Accessibility2 {
+    my ($r,$uname,$udom,$fn,$identifier) = @_;
+    my $warning = &lock_warning('Checking Accessibility');
+    if ($warning) {
+        $r->print($warning);
+        return;
+    }
+    if ((-e $fn) && ((-d $fn) || ($fn =~ /\.(problem|exam|quiz|assess|survey|xml|x?html?)$/))) {
+        my (@include,%options);
+        if (-d $fn) {
+            my @filetypes = qw(problem exam quiz assess survey xml html xhtml htm xhtm);
+            my %oktypes;
+            map { $oktypes{$_} = 1; } @filetypes;
+            my @posstypes = &Apache::loncommon::get_env_multiple('form.filetype');
+            foreach my $type (@posstypes) {
+                if ($oktypes{$type}) {
+                    push(@include,$type);
+                }
+            }
+            $options{'types'} = join(',', at include);
+            if (exists($env{'form.recurse'})) {
+                $options{'recurse'} = 1;
+            }
+            my $key = 'cgi.'.$identifier.'.accessibility';
+            my $storestring = &Apache::lonnet::freeze_escape(\%options);
+            &Apache::lonnet::appenv({$key => $storestring});
+        }
+        if (@include || !-d $fn) {
+            my $wcag;
+            if ($env{'form.standard'} =~ /^2(0|1|2)$/) {
+                $wcag = $env{'form.standard'};
+            } else {
+                $wcag = '22';
+            }
+            if ($env{'form.compliance'} =~ /^a{1,3}$/) {
+                $wcag .= $env{'form.compliance'};
+            } else {
+                $wcag .= 'aa';
+            }
+            my $axedir = $Apache::lonnet::perlvar{'lonAxeDir'};
+            if ($axedir) {
+                my $filename = "$axedir/$env{'user.name'}_$env{'user.domain'}_axe_$identifier.dat";
+                if (open(my $fh,'>',$filename)) {
+                    print $fh $fn;
+                    close($fh);
+                    &Apache::lonnet::appenv({'cgi.'.$identifier.'.file' => $filename,
+                                             'cgi.'.$identifier.'.wcag' => $wcag,
+                                             'cgi.'.$identifier.'.user' => $env{'user.name'},
+                                             'cgi.'.$identifier.'.domain' => $env{'user.domain'},
+                                             'cgi.'.$identifier.'.authoruname' => $uname,
+                                             'cgi.'.$identifier.'.authorudom' => $udom});
+                    my $continue_text = &mt('Continue');
+                    my $loadmsg = &mt('Please be patient while the Accessibility Testing environment loads');
+                    my $preamble = '<div id="LC_a11y" class="LC_info">'.
+                                   '<br />'.
+                                   $loadmsg.
+                                   '<br /></div>'.
+                                   '<div style="padding:0;clear:both;margin:0;border:0"></div>';
+                    my %prog_state = &Apache::lonhtmlcommon::Create_PrgWin($r,undef,$preamble);
+                    &Apache::lonhtmlcommon::Update_PrgWin($r,\%prog_state,&mt('Loading Accessibility Checker ...'));
+                    $r->print(<<END);
+<br />
+<meta http-equiv="Refresh" content="0; url=/cgi-bin/lonaxe.pl?$identifier" />
+END
+                    $r->rflush();
+                } else {
+                    $r->print('Could not open file to store list of resources.');
+                }
+            } else {
+                $r->print('Could not determine directory where list of resources is stored.');
+            }
+        } elsif (-d $fn) {
+            $r->print('No resource types selected. Nothing to do.');
+        } else {
+            $r->print('Accessibility checking unavailable for this resource type.');
+        }
+    } else {
+        $r->print('Accessibility checking unavailable for this resource type.');
+    }
+    return;
+}
+
 =pod
 
 =item NewFile1
@@ -1254,6 +1450,8 @@
                          .'</p></form>'
                 );
             }
+        } elsif ($env{'form.action'} eq 'accessibility') {
+            &Accessibility1($r,$fn);
         } elsif ($env{'form.action'} eq 'copy') {
 	    if ($newfilename) {
 	        &Copy1($r, $uname, $udom, $fn, $newfilename);
@@ -1693,6 +1891,9 @@
             $r->print(&mt('You do not have permission to export to an archive file in this Authoring Space'));
         }
         return;
+    } elsif ($env{'form.action'} eq 'accessibility') {
+        &Accessibility2($r,$uname,$udom,$fn,$identifier);
+        return;
     } elsif ($env{'form.action'} eq 'rename' ||
 	     $env{'form.action'} eq 'move') {
 	if($env{'form.newfilename'}) {
@@ -2040,6 +2241,22 @@
                 $args->{'add_entries'} = { onload => "resetForm()" };
             }
         }
+    } elsif ($env{'form.action'} eq 'accessibility') {
+        if ($env{'form.phase'} eq 'two') {
+            $identifier = &Apache::loncommon::get_cgi_id();
+        } else {
+            my $check_uncheck_js = &Apache::loncommon::check_uncheck_jscript();
+            $js = <<"ENDJS";
+<script type="text/javascript">
+// <![CDATA[
+
+$check_uncheck_js
+
+// ]]>
+</script>
+
+ENDJS
+        }
     }
     my $londocroot = $r->dir_config('lonDocRoot');
     my $trailfile = $fn;
@@ -2076,7 +2293,7 @@
                   &Apache::loncommon::CSTR_pageheader($trailfile))
     );
 
-    unless ($env{'form.action'} eq 'archive') {
+    unless (($env{'form.action'} eq 'archive') || ($env{'form.action'} eq 'accessibility')) {
         $r->print('<p>'.&mt('Location').': '.&display($fn).'</p>');
     }
 
@@ -2098,6 +2315,7 @@
         'newdir'          => 'New Directory',
         'decompress'      => 'Decompress',
         'archive'         => 'Export directory to archive file',
+        'accessibility'   => 'Check Accessibility',
         'copy'            => 'Copy',
         'newfile'         => 'New Resource',
 	'newhtmlfile'     => 'New Resource',
Index: loncom/interface/lonmenu.pm
diff -u loncom/interface/lonmenu.pm:1.572 loncom/interface/lonmenu.pm:1.573
--- loncom/interface/lonmenu.pm:1.572	Wed Feb 18 20:09:03 2026
+++ loncom/interface/lonmenu.pm	Tue Mar 31 23:29:35 2026
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Routines to control the menu
 #
-# $Id: lonmenu.pm,v 1.572 2026/02/18 20:09:03 raeburn Exp $
+# $Id: lonmenu.pm,v 1.573 2026/03/31 23:29:35 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -1302,6 +1302,9 @@
 ENDMENUITEMS
                     }
                 }
+                $menuitems .= (<<ENDMENUITEMS);
+s&7&8&accessibility-22x22.png&Accessibility&dir[_1]&gocstr('/adm/cfile?action=accessibility','$esc_currdir')&Check Accessibility
+ENDMENUITEMS
             } else {
                 $currdir =~ s|[^/]+$||;
 		my $cleandisfn = &Apache::loncommon::escape_single($thisdisfn);
@@ -1346,6 +1349,11 @@
 s&7&2&prt.png&Print&printout[_1]&gocstr('/adm/printout','/priv/$udom/$uname/$cleandisfn')&Prepare a printable document
 ENDMENUITEMS
                 }
+                if ($thisdisfn=~/\.problem|exam|quiz|assess|survey|xml|x?html?/) {
+                    $menuitems .= (<<ENDMENUITEMS);
+s&7&8&accessibility-22x22.png&Accessibility&dir[_1]&gocstr('/adm/cfile?action=accessibility','/priv/$udom/$uname/$cleandisfn')&Check Accessibility
+ENDMENUITEMS
+                }
 #
 # "Exit Daxe" in Functions menu when using Daxe
 #
@@ -1937,7 +1945,7 @@
     } elsif ($env{'request.noversionuri'} !~ m{^/adm/(navmaps|viewclasslist)(\?|$)}) {
         if ($env{'request.state'} eq 'construct') {
             &Apache::lonhtmlcommon::add_breadcrumb_tool(
-                'advtools', @funcs[61,73,74,71,72,77]);
+                'advtools', @funcs[61,73,74,71,72,77,78]);
         } else {
             &Apache::lonhtmlcommon::add_breadcrumb_tool(
                 'advtools', @funcs[61,71,72,73,74,75,92]);
Index: loncom/node.js/axe/lonaxe.pl
diff -u loncom/node.js/axe/lonaxe.pl:1.3 loncom/node.js/axe/lonaxe.pl:1.4
--- loncom/node.js/axe/lonaxe.pl:1.3	Tue Jan 13 03:18:24 2026
+++ loncom/node.js/axe/lonaxe.pl	Tue Mar 31 23:29:35 2026
@@ -1,6 +1,6 @@
 #!/usr/bin/perl
 $|=1;
-# $Id: lonaxe.pl,v 1.3 2026/01/13 03:18:24 raeburn Exp $
+# $Id: lonaxe.pl,v 1.4 2026/03/31 23:29:35 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -34,6 +34,14 @@
 use LONCAPA::Configuration;
 use LONCAPA::loncgi;
 use LONCAPA::AxeRunner;
+use File::Find;
+
+our $maxdepth = 0;
+our %included = ();
+our $recurse = '';
+our $prefix = '';
+our $totalfiles = 0;
+our $fh;
 
 if (! &LONCAPA::loncgi::check_cookie_and_load_env()) {
     print <<END;
@@ -56,38 +64,105 @@
 $outfile =~s/\.dat$/.txt/;
 my $csvfile = $outfile;
 $csvfile =~s/\.txt/.csv/;
-my $nummain = $env{'cgi.'.$identifier.'.main'};
-my $numsupp = $env{ 'cgi.'.$identifier.'.supp'};
-my $crstype = $env{ 'cgi.'.$identifier.'.crstype'};
-my %from_cgi_env = (
-                     uname => $env{'cgi.'.$identifier.'.user'},
-                     udom  => $env{'cgi.'.$identifier.'.domain'},
-                     cnum  => $env{'cgi.'.$identifier.'.cnum'},
-                     cdom  => $env{'cgi.'.$identifier.'.cdom'},
-                   );
 my %perlvar=%{&LONCAPA::Configuration::read_conf('loncapa.conf')};
 &Apache::lonlocal::get_language_handle();
+
+my ($nummain,$numsupp,$crstype,$is_course,$privurl);
+if (($env{'cgi.'.$identifier.'.authoruname'} ne '') &&
+    ($env{'cgi.'.$identifier.'.authorudom'} ne '')) {
+    my $auname = $env{'cgi.'.$identifier.'.authoruname'};
+    my $audom = $env{'cgi.'.$identifier.'.authorudom'};
+    my $fn;
+    if (open($fh,'<',$filename)) {
+        $fn = <$fh>;
+        close($fh);
+        if ($fn =~ m{/priv/$audom/$auname/}) {
+            my ($authorname,$authordom)=&Apache::lonnet::constructaccess($fn);
+            if (($authorname eq $auname) && ($authordom eq $audom)) {
+                $privurl = $fn;
+                my $londocroot = $perlvar{'lonDocRoot'};
+                my @posstypes = qw(problem exam quiz assess survey xml html xhtml htm xhtm);
+                $privurl =~ s/^\Q$londocroot\E//;
+                $privurl =~s {/\./}{/}g;
+                if ((-d $fn) && (open($fh,'>',$filename))) {
+                    my $hashref = &Apache::lonnet::thaw_unescape($env{'cgi.'.$identifier.'.accessibility'});
+                    if (ref($hashref) eq 'HASH') {
+                        if ($hashref->{'recurse'}) {
+                            $recurse = 1;
+                        } else {
+                            $recurse = 0;
+                        }
+                        if ($hashref->{'types'}) {
+                            my %possincluded;
+                            map { $possincluded{$_} = 1; } split(/,/,$hashref->{'types'});
+                            foreach my $type (@posstypes) {
+                                if ($possincluded{$type}) {
+                                    $included{$type} = 1;
+                                }
+                            }
+                        }
+                    }
+                    $prefix = $fn;
+                    $maxdepth = $prefix =~ tr{/}{};
+                    find(
+                         {preprocess => \&filter_files,
+                          wanted     => \&store_names,
+                          no_chdir   => 1,
+                         },$fn);
+                    close($fh);
+                } elsif ((!-d $fn) && (-e $fn)) {
+                    my ($ext) = ($fn =~ /\.(.+)$/);
+                    if (grep(/^$ext$/, at posstypes)) {
+                        $totalfiles = 1;
+                    }
+                }
+            }
+        }
+    }
+} else {
+    $nummain = $env{'cgi.'.$identifier.'.main'};
+    $numsupp = $env{'cgi.'.$identifier.'.supp'};
+    $crstype = $env{'cgi.'.$identifier.'.crstype'};
+    $is_course = 1;
+}
 &Apache::loncommon::content_type(undef,'text/html');
 $env{'request.noversionuri'} = '/cgi-bin/lonaxe.pl';
 
 # Breadcrumbs
-my $brcrum = [{'href' => '/adm/coursedocs?tools=1',
-               'text' => "$crstype Editor"},
-              {'href' => 'javascript:document.wcagresults.submit();',
-               'text' => "Choose Resources"},
-              {'href' => '',
-               'text' => 'Accessibility Results'}];
-
+my ($brcrum,$formaction);
+if ($is_course) {
+    $brcrum = [{'href' => '/adm/coursedocs?tools=1',
+                'text' => "$crstype Editor"},
+               {'href' => 'javascript:document.wcagresults.submit();',
+                'text' => "Choose Resources"},
+               {'href' => '',
+                'text' => 'Accessibility Results'}];
+} else {
+    $brcrum = [{'href' => "$privurl",
+                'text' => 'Authoring Space'},
+               {'href' => "javascript:gocstr('/adm/cfile?action=accessibility','$privurl');",
+                'text' => "File Operation"},
+               {'href' => '',
+                'text' => 'Accessibility Results'}];
+}
 print &Apache::loncommon::start_page('Accessibility Checking',
                                      undef,
                                      {'bread_crumbs' => $brcrum,});
-print <<ENDFORM;
-<div class="LC_landmark" role="main" id="LC_main_content" enctype="application/x-www-form-urlencoded">
+print '<div class="LC_landmark" role="main" id="LC_main_content" enctype="application/x-www-form-urlencoded">'."\n";
+if ($is_course) {
+    print <<ENDFORM;
 <form name="wcagresults" action="/adm/coursedocs" method="post">
 <input type="hidden" name="wcagcheck" value="1">
 <input type="hidden" name="tools" value="1">
 </form>
 ENDFORM
+} else {
+    print <<ENDFORM;
+<form name="constspace" action="/adm/cfile?action=accessibility" method="post">
+<input type="hidden" name="filename" value="$privurl" />
+</form>
+ENDFORM
+}
 
 my $linked_id = $env{'user.linkedenv'};
 my $sessionfile = $env{'user.environment'};
@@ -104,7 +179,7 @@
 }
 
 my %lt = &Apache::lonlocal::texthash(
-             ple => 'Please so not switch roles, logout, or quit the browser until accessibility check is complete.',
+             ple => 'Please do not switch roles, logout, or quit the browser until accessibility check is complete.',
              res => 'Resource',
              sta => 'Status',
              vio => 'Violations',
@@ -144,7 +219,12 @@
     my $now = time;
     $lock=&Apache::lonnet::set_lock("Checking Accessibility ($now)");
     if (&LONCAPA::AxeRunner::launch($cookieid,$handle,$linked_id,$hostname,$wcag) eq 'ok') {
-        my $number_of_files = $nummain + $numsupp;
+        my $number_of_files;
+        if ($is_course) {
+            $number_of_files = $nummain + $numsupp;
+        } else {
+            $number_of_files = $totalfiles;
+        }
         if ($number_of_files) {
             my $preamble = '<div id="LC_wcag_axe" class="LC_info">'.
                            '<br />'.
@@ -154,7 +234,7 @@
             my %prog_state = &Apache::lonhtmlcommon::Create_PrgWin('',$number_of_files,$preamble);
             my (%errors, at passed, at failed);
             print "<br />";
-            if (open(my $fh,'<',$filename)) {
+            if (open($fh,'<',$filename)) {
                 my @items;
                 while (my $line = <$fh>) {
                     chomp($line);
@@ -166,12 +246,17 @@
                     if ((open($outfh,'>',$outfile)) && (open($csvfh,'>',$csvfile))) {
                         print $csvfh "\"$lt{'res'}\",\"$lt{'sta'}\",\"$lt{'vio'}\"\n";
                         foreach my $item (@items) {
-                            my ($type,$dest,$title) = split(/\0/,$item);
                             my $querystr = '?inhibitmenu=yes';
-                            my $url = $dest;
-                            if ($type eq 'M') {
-                                $querystr .= '&symb='.$dest;
-                                $url = &Apache::lonnet::clutter((&Apache::lonnet::decode_symb($dest))[2]);
+                            my $url;
+                            if ($is_course) {
+                                my ($type,$dest,$title) = split(/\0/,$item);
+                                $url = $dest;
+                                if ($type eq 'M') {
+                                    $querystr .= '&symb='.$dest;
+                                    $url = &Apache::lonnet::clutter((&Apache::lonnet::decode_symb($dest))[2]);
+                                }
+                            } else {
+                                $url = $privurl.$item;
                             }
                             if ($url ne '') { 
                                 my ($violations,$details) =
@@ -186,7 +271,7 @@
                                     print $csvfh "\"$url\",\"$lt{'pass'}\",\"0\"\n";
                                 } else {
                                     push(@failed,$url);
-                                    print $outfh &mt('[quant,_1,violation] for[_2]',
+                                    print $outfh &mt('[quant,_1,violation] for [_2]',
                                                      $violations,$url)."\n".$details."\n\n";
                                     print $csvfh "\"$url\",\"$lt{'fail'}\",\"$violations\"\n";
                                 }
@@ -248,5 +333,40 @@
     }
 }
 print &Apache::loncommon::end_page();
+# Reset
+$maxdepth = 0;
+%included = ();
+$recurse = '';
+$prefix = '';
+$totalfiles = 0;
+
 exit;
 
+sub filter_files {
+    my @PossibleFiles = @_;
+    my @ChosenFiles;
+    foreach my $file (@PossibleFiles) {
+        if (-d $File::Find::dir."/".$file) {
+            if (!$recurse) {
+                my $depth = $File::Find::dir =~ tr[/][];
+                next unless ($depth < $maxdepth-1);
+            }
+            push(@ChosenFiles,$file);
+        } else {
+            next if ($file =~ /^\./);
+            my ($extension) = ($file =~ /\.([^.]+)$/);
+            if ($included{$extension}) {
+                push(@ChosenFiles,$file);
+            }
+        }
+    }
+    return @ChosenFiles;
+}
+
+sub store_names {
+    my $filename = $File::Find::name;
+    next if (-d $filename);
+    $totalfiles ++;
+    $filename =~ s{^$prefix}{};
+    print $fh "$filename\n";
+}


More information about the LON-CAPA-cvs mailing list