[LON-CAPA-cvs] cvs: loncom /homework grades.pm /interface domainprefs.pm lonconfigsettings.pm /lonnet/perl lonnet.pm
raeburn
raeburn at source.lon-capa.org
Sun Jan 27 09:40:04 EST 2019
raeburn Sun Jan 27 14:40:04 2019 EDT
Modified files:
/loncom/interface domainprefs.pm lonconfigsettings.pm
/loncom/homework grades.pm
/loncom/lonnet/perl lonnet.pm
Log:
- Uploaded bubblesheet data can consist of comma separated values.
- Data will be converted to one of formats specified in bubblesheet
format file, prior to saving in scantron_orig_* file.
- Domain configuration for bubblesheet data format allows order of
columns in csv data to be specified.
- &get_scantronformat_file and &get_scantron_config moved from grades.pm
to lonnet.pm to facilitate re-use.
-------------- next part --------------
Index: loncom/interface/domainprefs.pm
diff -u loncom/interface/domainprefs.pm:1.345 loncom/interface/domainprefs.pm:1.346
--- loncom/interface/domainprefs.pm:1.345 Wed Dec 26 20:10:24 2018
+++ loncom/interface/domainprefs.pm Sun Jan 27 14:39:48 2019
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Handler to set domain-wide configuration settings
#
-# $Id: domainprefs.pm,v 1.345 2018/12/26 20:10:24 raeburn Exp $
+# $Id: domainprefs.pm,v 1.346 2019/01/27 14:39:48 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -394,11 +394,12 @@
modify => \&modify_usermodification,
},
'scantron' =>
- { text => 'Bubblesheet format file',
+ { text => 'Bubblesheet format',
help => 'Domain_Configuration_Scantron_Format',
- header => [ {col1 => 'Item',
- col2 => '',
- }],
+ header => [ {col1 => 'Bubblesheet format file',
+ col2 => ''},
+ {col1 => 'Bubblesheet data upload formats',
+ col2 => 'Settings'}],
print => \&print_scantron,
modify => \&modify_scantron,
},
@@ -627,6 +628,9 @@
if (grep(/^contacts$/, at actions)) {
$js .= &contacts_javascript();
}
+ if (grep(/^scantron$/, at actions)) {
+ $js .= &scantron_javascript();
+ }
&Apache::lonconfigsettings::display_settings($r,$dom,$phase,$context,\@prefs_order,\%prefs,\%domconfig,$confname,$js);
} else {
# check if domconfig user exists for the domain.
@@ -828,6 +832,8 @@
$output .= $item->{'print'}->('top',$dom,$settings,\$rowtotal);
} elsif ($action eq 'coursecategories') {
$output .= $item->{'print'}->('top',$dom,$item,$settings,\$rowtotal);
+ } elsif ($action eq 'scantron') {
+ $output .= $item->{'print'}->($r,'top',$dom,$confname,$settings,\$rowtotal);
} elsif ($action eq 'login') {
if ($numheaders == 4) {
$colspan = ' colspan="2"';
@@ -932,6 +938,8 @@
($action eq 'defaults') || ($action eq 'directorysrch') ||
($action eq 'helpsettings')) {
$output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
+ } elsif ($action eq 'scantron') {
+ $output .= $item->{'print'}->($r,'bottom',$dom,$confname,$settings,\$rowtotal);
} elsif ($action eq 'ssl') {
$output .= $item->{'print'}->('connto',$dom,$settings,\$rowtotal).'
</table>
@@ -1113,8 +1121,6 @@
($action eq 'serverstatuses') || ($action eq 'loadbalancing') ||
($action eq 'ltitools') || ($action eq 'lti')) {
$output .= $item->{'print'}->($dom,$settings,\$rowtotal);
- } elsif ($action eq 'scantron') {
- $output .= &print_scantronformat($r,$dom,$confname,$settings,\$rowtotal);
}
}
$output .= '
@@ -7974,6 +7980,48 @@
return (\%titles);
}
+sub print_scantron {
+ my ($r,$position,$dom,$confname,$settings,$rowtotal) = @_;
+ if ($position eq 'top') {
+ return &print_scantronformat($r,$dom,$confname,$settings,\$rowtotal);
+ } else {
+ return &print_scantronconfig($dom,$settings,\$rowtotal);
+ }
+}
+
+sub scantron_javascript {
+ return <<"ENDSCRIPT";
+
+<script type="text/javascript">
+// <![CDATA[
+
+function toggleScantron(form) {
+ if (document.getElementById('scantroncsv_cols')) {
+ var csvfieldset = document.getElementById('scantroncsv_cols');
+ if (document.getElementById('scantronconfcsv')) {
+ var scantroncsv = document.getElementById('scantronconfcsv');
+ if (scantroncsv.checked) {
+ csvfieldset.style.display = 'inline-block';
+ } else {
+ csvfieldset.style.display = 'none';
+ var csvselects = document.getElementsByClassName('scantronconfig_csv');
+ if (csvselects.length) {
+ for (var j=0; j<csvselects.length; j++) {
+ csvselects[j].selectedIndex = 0;
+ }
+ }
+ }
+ }
+ }
+ return;
+}
+// ]]>
+</script>
+
+ENDSCRIPT
+
+}
+
sub print_scantronformat {
my ($r,$dom,$confname,$settings,$rowtotal) = @_;
my $itemcount = 1;
@@ -8000,8 +8048,8 @@
if ($configuserok eq 'ok') {
if ($author_ok eq 'ok') {
my %legacyfile = (
- default => $Apache::lonnet::perlvar{'lonTabDir'}.'/default_scantronformat.tab',
- custom => $Apache::lonnet::perlvar{'lonTabDir'}.'/scantronformat.tab',
+ default => $Apache::lonnet::perlvar{'lonTabDir'}.'/default_scantronformat.tab',
+ custom => $Apache::lonnet::perlvar{'lonTabDir'}.'/scantronformat.tab',
);
my %md5chk;
foreach my $type (keys(%legacyfile)) {
@@ -8010,7 +8058,7 @@
}
if ($md5chk{'default'} ne $md5chk{'custom'}) {
foreach my $type (keys(%legacyfile)) {
- ($scantronurls{$type},my $error) =
+ ($scantronurls{$type},my $error) =
&legacy_scantronformat($r,$dom,$confname,
$type,$legacyfile{$type},
$scantronurls{$type},
@@ -8021,13 +8069,13 @@
}
if (keys(%error) == 0) {
$is_custom = 1;
- $confhash{'scantron'}{'scantronformat'} =
+ $confhash{'scantron'}{'scantronformat'} =
$scantronurls{'custom'};
- my $putresult =
+ my $putresult =
&Apache::lonnet::put_dom('configuration',
\%confhash,$dom);
if ($putresult ne 'ok') {
- $error{'custom'} =
+ $error{'custom'} =
'<span class="LC_error">'.
&mt('An error occurred updating the domain configuration: [_1]',$putresult).'</span>';
}
@@ -8147,6 +8195,96 @@
return ($url,$error);
}
+sub print_scantronconfig {
+ my ($dom,$settings,$rowtotal) = @_;
+ my $itemcount = 2;
+ my $is_checked = ' checked="checked"';
+ my $currcsvsty = 'none';
+ my ($datatable,%csvfields,%checked,%onclick);
+ my @fields = &scantroncsv_fields();
+ my %titles = &scantronconfig_titles();
+ if (ref($settings) eq 'HASH') {
+ if (ref($settings->{config}) eq 'HASH') {
+ if ($settings->{config}->{dat}) {
+ $checked{'dat'} = $is_checked;
+ }
+ if (ref($settings->{config}->{csv}) eq 'HASH') {
+ %csvfields = %{$settings->{config}->{csv}};
+ if (keys(%csvfields) > 0) {
+ $checked{'csv'} = $is_checked;
+ $currcsvsty = 'inline-block';
+ }
+ }
+ } else {
+ $checked{'dat'} = $is_checked;
+ }
+ } else {
+ $checked{'dat'} = $is_checked;
+ }
+ $onclick{'csv'} = ' onclick="toggleScantron(this.form);"';
+ my $css_class = $itemcount%2? ' class="LC_odd_row"':'';
+ $datatable = '<tr '.$css_class.'><td>'.&mt('Supported formats').'</td>'.
+ '<td class="LC_left_item" valign="top"><span class="LC_nobreak">';
+ foreach my $item ('dat','csv') {
+ my $id;
+ if ($item eq 'csv') {
+ $id = 'id="scantronconfcsv" ';
+ }
+ $datatable .= '<label><input type="checkbox" name="scantronconfig" '.$id.'value="'.$item.'"'.$checked{$item}.$onclick{$item}.' />'.
+ $titles{$item}.'</label>'.(' 'x3);
+ if ($item eq 'csv') {
+ $datatable .= '<fieldset style="display:'.$currcsvsty.'" id="scantroncsv_cols">'.
+ '<legend>'.&mt('CSV Column Mapping').'</legend>'.
+ '<table><tr><th>'.&mt('Field').'</th><th>'.&mt('Location').'</th></tr>'."\n";
+ foreach my $col (@fields) {
+ my $selnone;
+ if ($csvfields{$col} eq '') {
+ $selnone = ' selected="selected"';
+ }
+ $datatable .= '<tr><td>'.$titles{$col}.'</td>'.
+ '<td><select name="scantronconfig_csv_'.$col.'" class="scantronconfig_csv">'.
+ '<option value=""'.$selnone.'></option>';
+ for (my $i=0; $i<20; $i++) {
+ my $shown = $i+1;
+ my $sel;
+ unless ($selnone) {
+ if (exists($csvfields{$col})) {
+ if ($csvfields{$col} == $i) {
+ $sel = ' selected="selected"';
+ }
+ }
+ }
+ $datatable .= '<option value="'.$i.'"'.$sel.'>'.$shown.'</option>';
+ }
+ $datatable .= '</select></td></tr>';
+ }
+ $datatable .= '</table></fieldset>';
+ $itemcount ++;
+ }
+ }
+ $datatable .= '</td></tr>';
+ $$rowtotal ++;
+ return $datatable;
+}
+
+sub scantronconfig_titles {
+ return &Apache::lonlocal::texthash(
+ dat => 'Standard format (.dat)',
+ csv => 'Comma separated values (.csv)',
+ CODE => 'CODE',
+ ID => 'Student ID',
+ PaperID => 'Paper ID',
+ FirstName => 'First Name',
+ LastName => 'Last Name',
+ FirstQuestion => 'First Question Response',
+ Section => 'Section',
+ );
+}
+
+sub scantroncsv_fields {
+ return ('PaperID','LastName','FirstName','ID','Section','CODE','FirstQuestion');
+}
+
sub print_coursecategories {
my ($position,$dom,$hdritem,$settings,$rowtotal) = @_;
my $datatable;
@@ -14964,7 +15102,7 @@
my $custom = 'custom.tab';
my $default = 'default.tab';
my $servadm = $r->dir_config('lonAdmEMail');
- my ($configuserok,$author_ok,$switchserver) =
+ my ($configuserok,$author_ok,$switchserver) =
&config_check($dom,$confname,$servadm);
if ($env{'form.scantronformat.filename'} ne '') {
my $error;
@@ -15002,6 +15140,56 @@
}
}
}
+ my @fields = &scantroncsv_fields();
+ my %titles = &scantronconfig_titles();
+ my @formats = &Apache::loncommon::get_env_multiple('form.scantronformat');
+ my ($newdat,$currdat,%newcol,%currcol);
+ if (grep(/^dat$/, at formats)) {
+ $confhash{'scantron'}{config}{dat} = 1;
+ $newdat = 1;
+ } else {
+ $confhash{'scantron'}{config}{dat} = 0;
+ $newdat = 0;
+ }
+ if (grep(/^csv$/, at formats)) {
+ my %bynum;
+ foreach my $field (@fields) {
+ if ($env{'form.scantronconfig_csv_'.$field} =~ /^(\d+)$/) {
+ my $posscol = $1;
+ if (($posscol < 20) && (!$bynum{$posscol})) {
+ $confhash{'scantron'}{config}{csv}{$field} = $posscol;
+ $bynum{$posscol} = $field;
+ $newcol{$field} = $posscol;
+ }
+ }
+ }
+ }
+ $currdat = 1;
+ if (ref($domconfig{'scantron'}) eq 'HASH') {
+ if (ref($domconfig{'scantron'}{'config'}) eq 'HASH') {
+ if (!$domconfig{'scantron'}{'config'}{'dat'}) {
+ $currdat = 0;
+ }
+ if (ref($domconfig{'scantron'}{'config'}{'csv'}) eq 'HASH') {
+ %currcol = %{$domconfig{'scantron'}{'config'}{'csv'}};
+ }
+ }
+ }
+ if ($currdat != $newdat) {
+ $changes{'config'} = 1;
+ } else {
+ foreach my $field (@fields) {
+ if ($currcol{$field} ne '') {
+ if ($currcol{$field} ne $newcol{$field}) {
+ $changes{'config'} = 1;
+ last;
+ }
+ } elsif ($newcol{$field} ne '') {
+ $changes{'config'} = 1;
+ last;
+ }
+ }
+ }
if (keys(%confhash) > 0) {
my $putresult = &Apache::lonnet::put_dom('configuration',\%confhash,
$dom);
@@ -15009,22 +15197,44 @@
if (keys(%changes) > 0) {
if (ref($confhash{'scantron'}) eq 'HASH') {
$resulttext = &mt('Changes made:').'<ul>';
- if ($confhash{'scantron'}{'scantronformat'} eq '') {
- $resulttext .= '<li>'.&mt('[_1] bubblesheet format file removed; [_2] file will be used for courses in this domain.',$custom,$default).'</li>';
- } else {
- $resulttext .= '<li>'.&mt('Custom bubblesheet format file ([_1]) uploaded for use with courses in this domain.',$custom).'</li>';
+ if ($changes{'scantronformat'}) {
+ if ($confhash{'scantron'}{'scantronformat'} eq '') {
+ $resulttext .= '<li>'.&mt('[_1] bubblesheet format file removed; [_2] file will be used for courses in this domain.',$custom,$default).'</li>';
+ } else {
+ $resulttext .= '<li>'.&mt('Custom bubblesheet format file ([_1]) uploaded for use with courses in this domain.',$custom).'</li>';
+ }
+ }
+ if ($changes{'config'}) {
+ if (ref($confhash{'scantron'}{'config'}) eq 'HASH') {
+ if ($confhash{'scantron'}{'config'}{'dat'}) {
+ $resulttext .= '<li>'.&mt('Bubblesheet data upload formats includes .dat format').'</li>';
+ }
+ if (ref($confhash{'scantron'}{'config'}{'csv'}) eq 'HASH') {
+ if (keys(%{$confhash{'scantron'}{'config'}{'csv'}})) {
+ '<li>'.&mt('Bubblesheet data upload formats includes .csv format, with following fields/column numbers supported:').'<ul>';
+ foreach my $field (@fields) {
+ if ($confhash{'scantron'}{'config'}{'csv'}{$field} ne '') {
+ my $showcol = $confhash{'scantron'}{'config'}{'csv'}{$field} + 1;
+ $resulttext .= '<li>'.$titles{$field}.': '.$showcol.'</li>';
+ }
+ }
+ $resulttext .= '</ul></li>';
+ }
+ }
+ } else {
+ $resulttext .= '<li>'.&mt('No bubblesheet data upload formats set -- will default to assuming .dat format').'</li>';
+ }
}
$resulttext .= '</ul>';
} else {
$resulttext = &mt('Changes made to bubblesheet format file.');
}
- $resulttext .= '</ul>';
&Apache::loncommon::devalidate_domconfig_cache($dom);
if (ref($lastactref) eq 'HASH') {
$lastactref->{'domainconfig'} = 1;
}
} else {
- $resulttext = &mt('No changes made to bubblesheet format file');
+ $resulttext = &mt('No changes made to bubblesheet format settings');
}
} else {
$resulttext = '<span class="LC_error">'.
Index: loncom/interface/lonconfigsettings.pm
diff -u loncom/interface/lonconfigsettings.pm:1.44 loncom/interface/lonconfigsettings.pm:1.45
--- loncom/interface/lonconfigsettings.pm:1.44 Tue Aug 14 21:42:40 2018
+++ loncom/interface/lonconfigsettings.pm Sun Jan 27 14:39:48 2019
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Handler to set domain-wide configuration settings
#
-# $Id: lonconfigsettings.pm,v 1.44 2018/08/14 21:42:40 raeburn Exp $
+# $Id: lonconfigsettings.pm,v 1.45 2019/01/27 14:39:48 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -251,6 +251,9 @@
}
}
}
+ if (grep(/^scantron$/, at actions)) {
+ $onload .= "toggleScantron('document.display');";
+ }
if ($onload) {
my %loaditems = (
'onload' => $onload,
Index: loncom/homework/grades.pm
diff -u loncom/homework/grades.pm:1.753 loncom/homework/grades.pm:1.754
--- loncom/homework/grades.pm:1.753 Tue Nov 20 19:14:14 2018
+++ loncom/homework/grades.pm Sun Jan 27 14:39:55 2019
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# The LON-CAPA Grading handler
#
-# $Id: grades.pm,v 1.753 2018/11/20 19:14:14 raeburn Exp $
+# $Id: grades.pm,v 1.754 2019/01/27 14:39:55 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -5805,7 +5805,7 @@
sub scantron_scantab {
my $result='<select name="scantron_format">'."\n";
$result.='<option></option>'."\n";
- my @lines = &get_scantronformat_file();
+ my @lines = &Apache::lonnet::get_scantronformat_file();
if (@lines > 0) {
foreach my $line (@lines) {
next if (($line =~ /^\#/) || ($line eq ''));
@@ -5817,62 +5817,6 @@
return $result;
}
-=pod
-
-=item get_scantronformat_file
-
- Returns an array containing lines from the scantron format file for
- the domain of the course.
-
- If a url for a custom.tab file is listed in domain's configuration.db,
- lines are from this file.
-
- Otherwise, if a default.tab has been published in RES space by the
- domainconfig user, lines are from this file.
-
- Otherwise, fall back to getting lines from the legacy file on the
- local server: /home/httpd/lonTabs/default_scantronformat.tab
-
-=cut
-
-sub get_scantronformat_file {
- my $cdom= $env{'course.'.$env{'request.course.id'}.'.domain'};
- my %domconfig = &Apache::lonnet::get_dom('configuration',['scantron'],$cdom);
- my $gottab = 0;
- my @lines;
- if (ref($domconfig{'scantron'}) eq 'HASH') {
- if ($domconfig{'scantron'}{'scantronformat'} ne '') {
- my $formatfile = &Apache::lonnet::getfile($Apache::lonnet::perlvar{'lonDocRoot'}.$domconfig{'scantron'}{'scantronformat'});
- if ($formatfile ne '-1') {
- @lines = split("\n",$formatfile,-1);
- $gottab = 1;
- }
- }
- }
- if (!$gottab) {
- my $confname = $cdom.'-domainconfig';
- my $default = $Apache::lonnet::perlvar{'lonDocRoot'}.'/res/'.$cdom.'/'.$confname.'/default.tab';
- my $formatfile = &Apache::lonnet::getfile($default);
- if ($formatfile ne '-1') {
- @lines = split("\n",$formatfile,-1);
- $gottab = 1;
- }
- }
- if (!$gottab) {
- my @domains = &Apache::lonnet::current_machine_domains();
- if (grep(/^\Q$cdom\E$/, at domains)) {
- my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.'/scantronformat.tab');
- @lines = <$fh>;
- close($fh);
- } else {
- my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.'/default_scantronformat.tab');
- @lines = <$fh>;
- close($fh);
- }
- }
- return @lines;
-}
-
=pod
=item scantron_CODElist
@@ -5957,21 +5901,13 @@
# Chunk of form to prompt for a scantron file upload.
$r->print('
- <br />
- '.&Apache::loncommon::start_data_table('LC_scantron_action').'
- '.&Apache::loncommon::start_data_table_header_row().'
- <th>
- '.&mt('Specify a bubblesheet data file to upload.').'
- </th>
- '.&Apache::loncommon::end_data_table_header_row().'
- '.&Apache::loncommon::start_data_table_row().'
- <td>
-');
+ <br />');
my $default_form_data=&defaultFormData($symb);
my $cdom= $env{'course.'.$env{'request.course.id'}.'.domain'};
my $cnum= $env{'course.'.$env{'request.course.id'}.'.num'};
my $alertmsg = &mt('Please use the browse button to select a file from your local directory.');
&js_escape(\$alertmsg);
+ my ($formatoptions,$formattitle,$formatjs) = &scantron_upload_dataformat($cdom);
$r->print(&Apache::lonhtmlcommon::scripttag('
function checkUpload(formname) {
if (formname.upfile.value == "") {
@@ -5979,24 +5915,42 @@
return false;
}
formname.submit();
- }'));
+ }'.$formatjs));
$r->print('
<form enctype="multipart/form-data" action="/adm/grades" name="rules" method="post">
'.$default_form_data.'
<input name="courseid" type="hidden" value="'.$cnum.'" />
<input name="domainid" type="hidden" value="'.$cdom.'" />
<input name="command" value="scantronupload_save" type="hidden" />
- '.&mt('File to upload: [_1]','<input type="file" name="upfile" size="50" />').'
- <br />
- <input type="button" onclick="javascript:checkUpload(this.form);" value="'.&mt('Upload Bubblesheet Data').'" />
- </form>
-');
+ '.&Apache::loncommon::start_data_table('LC_scantron_action').'
+ '.&Apache::loncommon::start_data_table_header_row().'
+ <th>
+ '.&mt('Specify a bubblesheet data file to upload.').'
+ </th>
+ '.&Apache::loncommon::end_data_table_header_row().'
+ '.&Apache::loncommon::start_data_table_row().'
+ <td>
+ '.&mt('File to upload: [_1]','<input type="file" name="upfile" size="50" />').'<br />'."\n");
+ if ($formatoptions) {
+ $r->print('</td>
+ '.&Apache::loncommon::end_data_table_row().'
+ '.&Apache::loncommon::start_data_table_row().'
+ <td>'.$formattitle.(' 'x2).$formatoptions.'
+ </td>
+ '.&Apache::loncommon::end_data_table_row().'
+ '.&Apache::loncommon::start_data_table_row().'
+ <td>'
+ );
+ } else {
+ $r->print(' <br />');
+ }
+ $r->print('<input type="button" onclick="javascript:checkUpload(this.form);" value="'.&mt('Upload Bubblesheet Data').'" />
+ </td>
+ '.&Apache::loncommon::end_data_table_row().'
+ '.&Apache::loncommon::end_data_table().'
+ </form>'
+ );
- $r->print('
- </td>
- '.&Apache::loncommon::end_data_table_row().'
- '.&Apache::loncommon::end_data_table().'
-');
}
# Chunk of form to prompt for a file to grade and how:
@@ -6109,98 +6063,6 @@
return;
}
-=pod
-
-=item get_scantron_config
-
- Parse and return the bubblesheet configuration line selected as a
- hash of configuration file fields.
-
- Arguments:
- which - the name of the configuration to parse from the file.
-
-
- Returns:
- If the named configuration is not in the file, an empty
- hash is returned.
- a hash with the fields
- name - internal name for the this configuration setup
- description - text to display to operator that describes this config
- CODElocation - if 0 or the string 'none'
- - no CODE exists for this config
- if -1 || the string 'letter'
- - a CODE exists for this config and is
- a string of letters
- Unsupported value (but planned for future support)
- if a positive integer
- - The CODE exists as the first n items from
- the question section of the form
- if the string 'number'
- - The CODE exists for this config and is
- a string of numbers
- CODEstart - (only matter if a CODE exists) column in the line where
- the CODE starts
- CODElength - length of the CODE
- IDstart - column where the student/employee ID starts
- IDlength - length of the student/employee ID info
- Qstart - column where the information from the bubbled
- 'questions' start
- Qlength - number of columns comprising a single bubble line from
- the sheet. (usually either 1 or 10)
- Qon - either a single character representing the character used
- to signal a bubble was chosen in the positional setup, or
- the string 'letter' if the letter of the chosen bubble is
- in the final, or 'number' if a number representing the
- chosen bubble is in the file (1->A 0->J)
- Qoff - the character used to represent that a bubble was
- left blank
- PaperID - if the scanning process generates a unique number for each
- sheet scanned the column that this ID number starts in
- PaperIDlength - number of columns that comprise the unique ID number
- for the sheet of paper
- FirstName - column that the first name starts in
- FirstNameLength - number of columns that the first name spans
-
- LastName - column that the last name starts in
- LastNameLength - number of columns that the last name spans
- BubblesPerRow - number of bubbles available in each row used to
- bubble an answer. (If not specified, 10 assumed).
-
-=cut
-
-sub get_scantron_config {
- my ($which) = @_;
- my @lines = &get_scantronformat_file();
- my %config;
- #FIXME probably should move to XML it has already gotten a bit much now
- foreach my $line (@lines) {
- my ($name,$descrip)=split(/:/,$line);
- if ($name ne $which ) { next; }
- chomp($line);
- my @config=split(/:/,$line);
- $config{'name'}=$config[0];
- $config{'description'}=$config[1];
- $config{'CODElocation'}=$config[2];
- $config{'CODEstart'}=$config[3];
- $config{'CODElength'}=$config[4];
- $config{'IDstart'}=$config[5];
- $config{'IDlength'}=$config[6];
- $config{'Qstart'}=$config[7];
- $config{'Qlength'}=$config[8];
- $config{'Qoff'}=$config[9];
- $config{'Qon'}=$config[10];
- $config{'PaperID'}=$config[11];
- $config{'PaperIDlength'}=$config[12];
- $config{'FirstName'}=$config[13];
- $config{'FirstNamelength'}=$config[14];
- $config{'LastName'}=$config[15];
- $config{'LastNamelength'}=$config[16];
- $config{'BubblesPerRow'}=$config[17];
- last;
- }
- return %config;
-}
-
=pod
=item username_to_idmap
@@ -6248,7 +6110,7 @@
Process a requested correction to a scanline.
Arguments:
- $scantron_config - hash from &get_scantron_config()
+ $scantron_config - hash from &Apache::lonnet::get_scantron_config()
$scan_data - hash of correction information
(see &scantron_getfile())
$line - existing scanline
@@ -6931,7 +6793,7 @@
sub scantron_process_corrections {
my ($r) = @_;
- my %scantron_config=&get_scantron_config($env{'form.scantron_format'});
+ my %scantron_config=&Apache::lonnet::get_scantron_config($env{'form.scantron_format'});
my ($scanlines,$scan_data)=&scantron_getfile();
my $classlist=&Apache::loncoursedata::get_classlist();
my $which=$env{'form.scantron_line'};
@@ -7100,7 +6962,7 @@
sub scantron_warning_screen {
my ($button_text,$symb)=@_;
my $title=&Apache::lonnet::gettitle($env{'form.selectpage'});
- my %scantron_config=&get_scantron_config($env{'form.scantron_format'});
+ my %scantron_config=&Apache::lonnet::get_scantron_config($env{'form.scantron_format'});
my $CODElist;
if ($scantron_config{'CODElocation'} &&
$scantron_config{'CODEstart'} &&
@@ -7256,7 +7118,7 @@
#get the student pick code ready
$r->print(&Apache::loncommon::studentbrowser_javascript());
my $nav_error;
- my %scantron_config=&get_scantron_config($env{'form.scantron_format'});
+ my %scantron_config=&Apache::lonnet::get_scantron_config($env{'form.scantron_format'});
my $max_bubble=&scantron_get_maxbubble(\$nav_error,\%scantron_config);
if ($nav_error) {
$r->print(&navmap_errormsg());
@@ -7716,7 +7578,7 @@
my %idmap=&username_to_idmap($classlist);
#get scantron line setup
- my %scantron_config=&get_scantron_config($env{'form.scantron_format'});
+ my %scantron_config=&Apache::lonnet::get_scantron_config($env{'form.scantron_format'});
my ($scanlines,$scan_data)=&scantron_getfile();
my $nav_error;
@@ -8186,7 +8048,7 @@
Arguments:
$r - Apache request object
- $scan_config - hash from &get_scantron_config()
+ $scan_config - hash from &Apache::lonnet::get_scantron_config()
$line - Number of the line being displayed.
$questionnum - Question number (may include subquestion)
$error - Type of error.
@@ -8350,7 +8212,7 @@
sub scantron_validate_CODE {
my ($r,$currentphase) = @_;
- my %scantron_config=&get_scantron_config($env{'form.scantron_format'});
+ my %scantron_config=&Apache::lonnet::get_scantron_config($env{'form.scantron_format'});
if ($scantron_config{'CODElocation'} &&
$scantron_config{'CODEstart'} &&
$scantron_config{'CODElength'}) {
@@ -8424,7 +8286,7 @@
&Apache::lonnet::decode_symb($env{'form.selectpage'});
#get scantron line setup
- my %scantron_config=&get_scantron_config($env{'form.scantron_format'});
+ my %scantron_config=&Apache::lonnet::get_scantron_config($env{'form.scantron_format'});
my ($scanlines,$scan_data)=&scantron_getfile();
my $navmap = Apache::lonnavmaps::navmap->new();
@@ -8606,7 +8468,7 @@
&Apache::lonnet::decode_symb($env{'form.selectpage'});
#get scantron line setup
- my %scantron_config=&get_scantron_config($env{'form.scantron_format'});
+ my %scantron_config=&Apache::lonnet::get_scantron_config($env{'form.scantron_format'});
my ($scanlines,$scan_data)=&scantron_getfile();
my $navmap = Apache::lonnavmaps::navmap->new();
@@ -8735,7 +8597,7 @@
}
}
if ($needs_hand_bubbles) {
- my %scantron_config=&get_scantron_config($env{'form.scantron_format'});
+ my %scantron_config=&Apache::lonnet::get_scantron_config($env{'form.scantron_format'});
my $bubbles_per_row = &bubblesheet_bubbles_per_row(\%scantron_config);
return &mt('The sequence to be graded contains response types which are handgraded.').'<p>'.
&mt('If you have already graded these by bubbling sheets to indicate points awarded, [_1]what point value is assigned to a filled last bubble in each row?','<br />').
@@ -8754,7 +8616,7 @@
}
my $default_form_data=&defaultFormData($symb);
- my %scantron_config=&get_scantron_config($env{'form.scantron_format'});
+ my %scantron_config=&Apache::lonnet::get_scantron_config($env{'form.scantron_format'});
my $bubbles_per_row = &bubblesheet_bubbles_per_row(\%scantron_config);
my ($scanlines,$scan_data)=&scantron_getfile();
my $classlist=&Apache::loncoursedata::get_classlist();
@@ -9149,6 +9011,7 @@
sub scantron_upload_scantron_data {
my ($r,$symb)=@_;
my $dom = $env{'request.role.domain'};
+ my ($formatoptions,$formattitle,$formatjs) = &scantron_upload_dataformat($dom);
my $domdesc = &Apache::lonnet::domain($dom,'description');
$r->print(&Apache::loncommon::coursebrowser_javascript($dom));
my $select_link=&Apache::loncommon::selectcourse_link('rules','courseid',
@@ -9188,6 +9051,7 @@
return;
}
+ '.$formatjs.'
'));
$r->print('
<h3>'.&mt('Send bubblesheet data to a course').'</h3>
@@ -9203,7 +9067,12 @@
&Apache::lonhtmlcommon::row_closure().
&Apache::lonhtmlcommon::row_title(&mt('Domain')).
'<input name="domainid" type="hidden" />'.$domdesc.
- &Apache::lonhtmlcommon::row_closure().
+ &Apache::lonhtmlcommon::row_closure());
+ if ($formatoptions) {
+ $r->print(&Apache::lonhtmlcommon::row_title($formattitle).$formatoptions.
+ &Apache::lonhtmlcommon::row_closure());
+ }
+ $r->print(
&Apache::lonhtmlcommon::row_title(&mt('File to upload')).
'<input type="file" name="upfile" size="50" />'.
&Apache::lonhtmlcommon::row_closure(1).
@@ -9216,6 +9085,78 @@
return '';
}
+sub scantron_upload_dataformat {
+ my ($dom) = @_;
+ my ($formatoptions,$formattitle,$formatjs);
+ $formatjs = <<'END';
+function toggleScantab(form) {
+ return;
+}
+END
+ my %domconfig = &Apache::lonnet::get_dom('configuration',['scantron'],$dom);
+ if (ref($domconfig{'scantron'}) eq 'HASH') {
+ if (ref($domconfig{'scantron'}{'config'}) eq 'HASH') {
+ if (keys(%{$domconfig{'scantron'}{'config'}}) > 1) {
+ if (($domconfig{'scantron'}{'config'}{'dat'}) &&
+ (ref($domconfig{'scantron'}{'config'}{'csv'}) eq 'HASH')) {
+ if (keys(%{$domconfig{'scantron'}{'config'}{'csv'}})) {
+ my ($onclick,$formatextra,$singleline);
+ my @lines = &Apache::lonnet::get_scantronformat_file();
+ my $count = 0;
+ foreach my $line (@lines) {
+ next if ($line =~ /^#/);
+ $singleline = $line;
+ $count ++;
+ }
+ if ($count > 1) {
+ $formatextra = '<div style="display:none" id="bubbletype">'.
+ &scantron_scantab().'</div>';
+ $onclick = ' onclick="toggleScantab(this.form);"';
+ $formatjs = <<"END";
+function toggleScantab(form) {
+ var divid = 'bubbletype';
+ if (document.getElementById(divid)) {
+ var radioname = 'fileformat';
+ var num = form.elements[radioname].length;
+ if (num) {
+ for (var i=0; i<num; i++) {
+ if (form.elements[radioname][i].checked) {
+ var chosen = form.elements[radioname][i].value;
+ if (chosen == 'dat') {
+ document.getElementById(divid).style.display = 'none';
+ } else if (chosen == 'csv') {
+ document.getElementById(divid).style.display = 'inline-block';
+ }
+ }
+ }
+ }
+ }
+ return;
+}
+
+END
+ } elsif ($count == 1) {
+ my $formatname = (split(/:/,$singleline,2))[0];
+ $formatextra = '<input type="hidden" name="scantron_format" value="'.$formatname.'" />';
+ }
+ $formattitle = &mt('File format');
+ $formatoptions = '<label><input name="fileformat" type="radio" value="dat" checked="checked"'.$onclick.' />'.
+ &mt('Plain Text (no delimiters)').
+ '</label>'.(' 'x2).
+ '<label><input name="fileformat" type="radio" value="csv"'.$onclick.' />'.
+ &mt('Comma separated values').'</label>'.$formatextra;
+ }
+ }
+ } elsif (keys(%{$domconfig{'scantron'}{'config'}}) == 1) {
+ if (keys(%{$domconfig{'scantron'}{'config'}{'csv'}})) {
+ $formattitle = &mt('Format of bubblesheet data file:');
+ $formatoptions = &scantron_scantab();
+ }
+ }
+ }
+ }
+ return ($formatoptions,$formattitle,$formatjs);
+}
sub scantron_upload_scantron_data_save {
my($r,$symb)=@_;
@@ -9242,8 +9183,34 @@
&mt('The file: [_1] you attempted to upload contained no information. Please check that you entered the correct filename.',
'<span class="LC_filename">'.&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"').'</span>'),1));
} else {
- my $result =
- &Apache::lonnet::userfileupload('upfile','','scantron','','','',
+ my %domconfig = &Apache::lonnet::get_dom('configuration',['scantron'],$env{'form.domainid'});
+ my $parser;
+ if (ref($domconfig{'scantron'}) eq 'HASH') {
+ if (ref($domconfig{'scantron'}{'config'}) eq 'HASH') {
+ my $is_csv;
+ my @possibles = keys(%{$domconfig{'scantron'}{'config'}});
+ if (@possibles > 1) {
+ if ($env{'form.fileformat'} eq 'csv') {
+ if (ref($domconfig{'scantron'}{'config'}{'csv'}) eq 'HASH') {
+ if (keys(%{$domconfig{'scantron'}{'config'}{'csv'}}) > 1) {
+ $is_csv = 1;
+ }
+ }
+ }
+ } elsif (@possibles == 1) {
+ if (ref($domconfig{'scantron'}{'config'}{'csv'}) eq 'HASH') {
+ if (keys(%{$domconfig{'scantron'}{'config'}{'csv'}}) > 1) {
+ $is_csv = 1;
+ }
+ }
+ }
+ if ($is_csv) {
+ $parser = $domconfig{'scantron'}{'config'}{'csv'};
+ }
+ }
+ }
+ my $result =
+ &Apache::lonnet::userfileupload('upfile','scantron','scantron',$parser,'','',
$env{'form.courseid'},$env{'form.domainid'});
if ($result =~ m{^/uploaded/}) {
$r->print(
@@ -9288,7 +9255,7 @@
$idmap{$lckey} = $idmap{$key};
}
my %unique_formats;
- my @formatlines = &get_scantronformat_file();
+ my @formatlines = &Apache::lonnet::get_scantronformat_file();
foreach my $line (@formatlines) {
chomp($line);
my @config = split(/:/,$line);
@@ -9436,7 +9403,7 @@
my (undef, undef, $sequence) = &Apache::lonnet::decode_symb($env{'form.selectpage'});
my %record;
my %scantron_config =
- &Apache::grades::get_scantron_config($env{'form.scantron_format'});
+ &Apache::lonnet::get_scantron_config($env{'form.scantron_format'});
my $bubbles_per_row = &bubblesheet_bubbles_per_row(\%scantron_config);
my ($scanlines,$scan_data)=&Apache::grades::scantron_getfile();
my $classlist=&Apache::loncoursedata::get_classlist();
@@ -10668,13 +10635,21 @@
}
sub startpage {
- my ($r,$symb,$crumbs,$onlyfolderflag,$nodisplayflag,$stuvcurrent,$stuvdisp,$nomenu,$js) = @_;
+ my ($r,$symb,$crumbs,$onlyfolderflag,$nodisplayflag,$stuvcurrent,$stuvdisp,$nomenu,$js,$onload) = @_;
+ my %args;
+ if ($onload) {
+ my %loaditems = (
+ 'onload' => $onload,
+ );
+ $args{'add_entries'} = \%loaditems;
+ }
if ($nomenu) {
- $r->print(&Apache::loncommon::start_page("Student's Version",$js,{'only_body' => '1'}));
+ $args{'only_body'} = 1;
+ $r->print(&Apache::loncommon::start_page("Student's Version",$js,\%args);
} else {
unshift(@$crumbs,{href=>&href_symb_cmd($symb,'gradingmenu'),text=>"Grading"});
- $r->print(&Apache::loncommon::start_page('Grading',$js,
- {'bread_crumbs' => $crumbs}));
+ $args{'bread_crumbs'} = $crumbs;
+ $r->print(&Apache::loncommon::start_page('Grading',$js,\%args));
&Apache::lonquickgrades::startGradeScreen($r,($env{'form.symb'}?'probgrading':'grading'));
}
unless ($nodisplayflag) {
@@ -10858,7 +10833,8 @@
&startpage($request,$symb,[{href=>'', text=>'Upload Scores'}],1,1);
$request->print(&csvuploadassign($request,$symb));
} elsif ($command eq 'scantron_selectphase' && $perm{'mgr'}) {
- &startpage($request,$symb,[{href=>'', text=>'Grade/Manage/Review Bubblesheets'}],1,1);
+ &startpage($request,$symb,[{href=>'', text=>'Grade/Manage/Review Bubblesheets'}],1,1,
+ undef,undef,undef,undef,'toggleScantab(document.rules);');
$request->print(&scantron_selectphase($request,undef,$symb));
} elsif ($command eq 'scantron_warning' && $perm{'mgr'}) {
&startpage($request,$symb,[{href=>'', text=>'Grade/Manage/Review Bubblesheets'}],1,1);
@@ -10872,7 +10848,8 @@
} elsif ($command eq 'scantronupload' &&
(&Apache::lonnet::allowed('usc',$env{'request.role.domain'})||
&Apache::lonnet::allowed('usc',$env{'request.course.id'}))) {
- &startpage($request,$symb,[{href=>'', text=>'Grade/Manage/Review Bubblesheets'}],1,1);
+ &startpage($request,$symb,[{href=>'', text=>'Grade/Manage/Review Bubblesheets'}],1,1,
+ undef,undef,undef,undef,'toggleScantab(document.rules);');
$request->print(&scantron_upload_scantron_data($request,$symb));
} elsif ($command eq 'scantronupload_save' &&
(&Apache::lonnet::allowed('usc',$env{'request.role.domain'})||
Index: loncom/lonnet/perl/lonnet.pm
diff -u loncom/lonnet/perl/lonnet.pm:1.1400 loncom/lonnet/perl/lonnet.pm:1.1401
--- loncom/lonnet/perl/lonnet.pm:1.1400 Sat Dec 29 16:50:06 2018
+++ loncom/lonnet/perl/lonnet.pm Sun Jan 27 14:40:02 2019
@@ -1,7 +1,7 @@
# The LearningOnline Network
# TCP networking package
#
-# $Id: lonnet.pm,v 1.1400 2018/12/29 16:50:06 raeburn Exp $
+# $Id: lonnet.pm,v 1.1401 2019/01/27 14:40:02 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -3905,13 +3905,16 @@
# input: $formname - the contents of the file are in $env{"form.$formname"}
# the desired filename is in $env{"form.$formname.filename"}
# $context - possible values: coursedoc, existingfile, overwrite,
-# canceloverwrite, or ''.
+# canceloverwrite, scantron or ''.
# if 'coursedoc': upload to the current course
# if 'existingfile': write file to tmp/overwrites directory
# if 'canceloverwrite': delete file written to tmp/overwrites directory
# $context is passed as argument to &finishuserfileupload
# $subdir - directory in userfile to store the file into
-# $parser - instruction to parse file for objects ($parser = parse)
+# $parser - instruction to parse file for objects ($parser = parse) or
+# if context is 'scantron', $parser is hashref of csv column mapping
+# (e.g.,{ PaperID => 0, LastName => 1, FirstName => 2, ID => 3,
+# Section => 4, CODE => 5, FirstQuestion => 9 }).
# $allfiles - reference to hash for embedded objects
# $codebase - reference to hash for codebase of java objects
# $desuname - username for permanent storage of uploaded file
@@ -4101,7 +4104,7 @@
}
}
}
- if ($parser eq 'parse') {
+ if (($context ne 'scantron') && ($parser eq 'parse')) {
if ((ref($mimetype)) && ($$mimetype eq 'text/html')) {
my $parse_result = &extract_embedded_items($filepath.'/'.$file,
$allfiles,$codebase);
@@ -4110,6 +4113,9 @@
' for embedded media: '.$parse_result);
}
}
+ } elsif (($context eq 'scantron') && (ref($parser) eq 'HASH')) {
+ my $format = $env{'form.scantron_format'};
+ &bubblesheet_converter($docudom,$filepath.'/'.$file,$parser,$format);
}
if (($thumbwidth =~ /^\d+$/) && ($thumbheight =~ /^\d+$/)) {
my $input = $filepath.'/'.$file;
@@ -4350,6 +4356,172 @@
return;
}
+sub bubblesheet_converter {
+ my ($cdom,$fullpath,$config,$format) = @_;
+ if ((&domain($cdom) ne '') &&
+ ($fullpath =~ m{^\Q$perlvar{'lonDocRoot'}/userfiles/$cdom/$match_courseid/scantron_orig}) &&
+ (-e $fullpath) && (ref($config) eq 'HASH') && ($format ne '')) {
+ my %csvcols = %{$config};
+ my %csvbynum = reverse(%csvcols);
+ my %scantronconf = &get_scantron_config($format,$cdom);
+ if (keys(%scantronconf)) {
+ my %bynum = (
+ $scantronconf{CODEstart} => 'CODEstart',
+ $scantronconf{IDstart} => 'IDstart',
+ $scantronconf{PaperID} => 'PaperID',
+ $scantronconf{FirstName} => 'FirstName',
+ $scantronconf{LastName} => 'LastName',
+ $scantronconf{Qstart} => 'Qstart',
+ );
+ my @ordered;
+ foreach my $item (sort { $a <=> $b } keys(%bynum)) {
+ push (@ordered,$bynum{$item}));
+ }
+ my %mapstart = (
+ CODEstart => 'CODE',
+ IDstart => 'ID',
+ PaperID => 'PaperID',
+ FirstName => 'FirstName',
+ LastName => 'LastName',
+ Qstart => 'FirstQuestion',
+ );
+ my %maplength = (
+ CODEstart => 'CODElength',
+ IDstart => 'IDlength',
+ PaperID => 'PaperIDlength',
+ FirstName => 'FirstNamelength',
+ LastName => 'LastNamelength',
+ );
+ if (open(my $fh,'<',$fullpath)) {
+ my $output;
+ while (my $line=<$fh>) {
+ $line =~ s{[\r\n]+$}{};
+ my %found;
+ my @values = split(/,/,$line);
+ my ($qstart,$record);
+ for (my $i=0; $i<@values; $i++) {
+ if (($qstart ne '') && ($i > $qstart)) {
+ $found{'FirstQuestion'} .= $values[$i];
+ } elsif (exists($csvbynum{$i})) {
+ if ($csvbynum{$i} eq 'FirstQuestion') {
+ $qstart = $i;
+ } else {
+ $values[$i] =~ s/^\s+//;
+ if ($csvbynum{$i} eq 'PaperID') {
+ while (length($values[$i]) < $scantronconf{$maplength{$csvbynum{$i}}}) {
+ $values[$i] = '0'.$values[$i];
+ }
+ }
+ }
+ $found{$csvbynum{$i}} = $values[$i];
+ }
+ }
+ foreach my $item (@ordered) {
+ my $currlength = 1+length($record);
+ my $numspaces = $scantronconf{$item} - $currlength;
+ if ($numspaces > 0) {
+ $record .= (' ' x $numspaces);
+ }
+ if (($mapstart{$item} ne '') && (exists($found{$mapstart{$item}}))) {
+ unless ($item eq 'Qstart') {
+ if (length($found{$mapstart{$item}}) > $scantronconf{$maplength{$item}}) {
+ $found{$mapstart{$item}} = substr($found{$mapstart{$item}},0,$scantronconf{$maplength{$item}});
+ }
+ }
+ $record .= $found{$mapstart{$item}};
+ }
+ }
+ $output .= "$record\n";
+ }
+ close($fh);
+ if ($output) {
+ if (open(my $fh,'>',$fullpath)) {
+ print $fh $output;
+ close($fh);
+ }
+ }
+ }
+ }
+ return;
+ }
+}
+
+sub get_scantron_config {
+ my ($which,$cdom) = @_;
+ my @lines = &get_scantronformat_file($cdom);
+ my %config;
+ #FIXME probably should move to XML it has already gotten a bit much now
+ foreach my $line (@lines) {
+ my ($name,$descrip)=split(/:/,$line);
+ if ($name ne $which ) { next; }
+ chomp($line);
+ my @config=split(/:/,$line);
+ $config{'name'}=$config[0];
+ $config{'description'}=$config[1];
+ $config{'CODElocation'}=$config[2];
+ $config{'CODEstart'}=$config[3];
+ $config{'CODElength'}=$config[4];
+ $config{'IDstart'}=$config[5];
+ $config{'IDlength'}=$config[6];
+ $config{'Qstart'}=$config[7];
+ $config{'Qlength'}=$config[8];
+ $config{'Qoff'}=$config[9];
+ $config{'Qon'}=$config[10];
+ $config{'PaperID'}=$config[11];
+ $config{'PaperIDlength'}=$config[12];
+ $config{'FirstName'}=$config[13];
+ $config{'FirstNamelength'}=$config[14];
+ $config{'LastName'}=$config[15];
+ $config{'LastNamelength'}=$config[16];
+ $config{'BubblesPerRow'}=$config[17];
+ last;
+ }
+ return %config;
+}
+
+sub get_scantronformat_file {
+ my ($cdom) = @_;
+ if ($cdom eq '') {
+ $cdom= $env{'course.'.$env{'request.course.id'}.'.domain'};
+ }
+ my %domconfig = &get_dom('configuration',['scantron'],$cdom);
+ my $gottab = 0;
+ my @lines;
+ if (ref($domconfig{'scantron'}) eq 'HASH') {
+ if ($domconfig{'scantron'}{'scantronformat'} ne '') {
+ my $formatfile = &getfile($perlvar{'lonDocRoot'}.$domconfig{'scantron'}{'scantronformat'});
+ if ($formatfile ne '-1') {
+ @lines = split("\n",$formatfile,-1);
+ $gottab = 1;
+ }
+ }
+ }
+ if (!$gottab) {
+ my $confname = $cdom.'-domainconfig';
+ my $default = $perlvar{'lonDocRoot'}.'/res/'.$cdom.'/'.$confname.'/default.tab';
+ my $formatfile = &getfile($default);
+ if ($formatfile ne '-1') {
+ @lines = split("\n",$formatfile,-1);
+ $gottab = 1;
+ }
+ }
+ if (!$gottab) {
+ my @domains = ¤t_machine_domains();
+ if (grep(/^\Q$cdom\E$/, at domains)) {
+ if (open(my $fh,'<',$perlvar{'lonTabDir'}.'/scantronformat.tab')) {
+ @lines = <$fh>;
+ close($fh);
+ }
+ } else {
+ if (open(my $fh,'<',$perlvar{'lonTabDir'}.'/default_scantronformat.tab')) {
+ @lines = <$fh>;
+ close($fh);
+ }
+ }
+ }
+ return @lines;
+}
+
sub removeuploadedurl {
my ($url)=@_;
my (undef,undef,$udom,$uname,$fname)=split('/',$url,5);
@@ -15135,6 +15307,89 @@
=back
+=head2 Bubblesheet Configuration
+
+=over 4
+
+=item *
+
+get_scantron_config($which)
+
+$which - the name of the configuration to parse from the file.
+
+Parses and returns the bubblesheet configuration line selected as a
+hash of configuration file fields.
+
+
+Returns:
+ If the named configuration is not in the file, an empty
+ hash is returned.
+
+ a hash with the fields
+ name - internal name for the this configuration setup
+ description - text to display to operator that describes this config
+ CODElocation - if 0 or the string 'none'
+ - no CODE exists for this config
+ if -1 || the string 'letter'
+ - a CODE exists for this config and is
+ a string of letters
+ Unsupported value (but planned for future support)
+ if a positive integer
+ - The CODE exists as the first n items from
+ the question section of the form
+ if the string 'number'
+ - The CODE exists for this config and is
+ a string of numbers
+ CODEstart - (only matter if a CODE exists) column in the line where
+ the CODE starts
+ CODElength - length of the CODE
+ IDstart - column where the student/employee ID starts
+ IDlength - length of the student/employee ID info
+ Qstart - column where the information from the bubbled
+ 'questions' start
+ Qlength - number of columns comprising a single bubble line from
+ the sheet. (usually either 1 or 10)
+ Qon - either a single character representing the character used
+ to signal a bubble was chosen in the positional setup, or
+ the string 'letter' if the letter of the chosen bubble is
+ in the final, or 'number' if a number representing the
+ chosen bubble is in the file (1->A 0->J)
+ Qoff - the character used to represent that a bubble was
+ left blank
+ PaperID - if the scanning process generates a unique number for each
+ sheet scanned the column that this ID number starts in
+ PaperIDlength - number of columns that comprise the unique ID number
+ for the sheet of paper
+ FirstName - column that the first name starts in
+ FirstNameLength - number of columns that the first name spans
+
+ LastName - column that the last name starts in
+ LastNameLength - number of columns that the last name spans
+ BubblesPerRow - number of bubbles available in each row used to
+ bubble an answer. (If not specified, 10 assumed).
+
+
+=item *
+
+get_scantronformat_file($cdom)
+
+$cdom - the course's domain (optional); if not supplied, uses
+domain for current $env{'request.course.id'}.
+
+Returns an array containing lines from the scantron format file for
+the domain of the course.
+
+If a url for a custom.tab file is listed in domain's configuration.db,
+lines are from this file.
+
+Otherwise, if a default.tab has been published in RES space by the
+domainconfig user, lines are from this file.
+
+Otherwise, fall back to getting lines from the legacy file on the
+local server: /home/httpd/lonTabs/default_scantronformat.tab
+
+=back
+
=head2 Resource Subroutines
=over 4
@@ -15832,6 +16087,7 @@
formname: same as for userfileupload()
fname: filename (including subdirectories) for the file
parser: if 'parse', will parse (html) file to extract references to objects, links etc.
+ if hashref, and context is scantron, will convert csv format to standard format
allfiles: reference to hash used to store objects found by parser
codebase: reference to hash used for codebases of java objects found by parser
thumbwidth: width (pixels) of thumbnail to be created for uploaded image
More information about the LON-CAPA-cvs
mailing list