');
- pDoc.write('');
- pDoc.write("$lt{'type'}<\\/b><\\/td> $lt{'incl'}<\\/b><\\/td> $lt{'mesa'}<\\/td><\\/tr>");
+ pDoc.write('';
- $endform.=&show_grading_menu_form($symb);
$request->print($endform);
}
return '';
@@ -2575,7 +2515,10 @@ sub get_last_submission {
my ($partid,$foo) = split(/submission$/,$key);
my $draft = $lasthash{$partid.'awarddetail'} eq 'DRAFT' ?
'Draft Copy ' : '';
- push(@string, join(':', $key, $hide, $draft.$lasthash{$key}));
+ #push(@string, join(':', $key, $hide, $draft.$lasthash{$key}));
+ push(@string, join(':', $key, $hide, $draft.(
+ ref($lasthash{$key}) eq 'ARRAY' ?
+ join(',', @{$lasthash{$key}}) : $lasthash{$key}) ));
}
}
if (!@string) {
@@ -2598,10 +2541,189 @@ sub keywords_highlight {
return $string;
}
+# For Tasks provide a mechanism to display previous version for one specific student
+
+sub show_previous_task_version {
+ my ($request,$symb) = @_;
+ if ($symb eq '') {
+ $request->print("Unable to handle ambiguous references.");
+
+ return '';
+ }
+ my ($uname,$udom) = ($env{'form.student'},$env{'form.userdom'});
+ my $usec = &Apache::lonnet::getsection($udom,$uname,$env{'request.course.id'});
+ if (!&canview($usec)) {
+ $request->print(
+ ''.
+ &mt('Unable to view previous version for requested student.').
+ ' '.&mt('([_1] in section [_2] in course id [_3])',
+ $uname.':'.$udom,$usec,$env{'request.course.id'}).
+ ' ');
+ return;
+ }
+ my $mode = 'both';
+ my $isTask = ($symb =~/\.task$/);
+ if ($isTask) {
+ if ($env{'form.previousversion'} =~ /^\d+$/) {
+ if ($env{'form.fullname'} eq '') {
+ $env{'form.fullname'} =
+ &Apache::loncommon::plainname($uname,$udom,'lastname');
+ }
+ my $probtitle=&Apache::lonnet::gettitle($symb);
+ $request->print("\n\n".
+ ' '.
+ '
'.&nameUserString(undef,$env{'form.fullname'},$uname,$udom).
+ ' '."\n");
+ &Apache::lonxml::clear_problem_counter();
+ $request->print(&show_problem($request,$symb,$uname,$udom,1,1,$mode,
+ {'previousversion' => $env{'form.previousversion'} }));
+ $request->print("\n");
+ }
+ }
+ return;
+}
+
+sub choose_task_version_form {
+ my ($symb,$uname,$udom,$nomenu) = @_;
+ my $isTask = ($symb =~/\.task$/);
+ my ($current,$version,$result,$js,$displayed,$rowtitle);
+ if ($isTask) {
+ my %record = &Apache::lonnet::restore($symb,$env{'request.course.id'},
+ $udom,$uname);
+ if (($record{'resource.0.version'} eq '') ||
+ ($record{'resource.0.version'} < 2)) {
+ return ($record{'resource.0.version'},
+ $record{'resource.0.version'},$result,$js);
+ } else {
+ $current = $record{'resource.0.version'};
+ }
+ if ($env{'form.previousversion'}) {
+ $displayed = $env{'form.previousversion'};
+ $rowtitle = &mt('Choose another version:')
+ } else {
+ $displayed = $current;
+ $rowtitle = &mt('Show earlier version:');
+ }
+ $result = '';
+ }
+ return ($current,$displayed,$result,$js);
+}
+
+sub previous_display_javascript {
+ my ($nomenu,$current) = @_;
+ my $js = <<"JSONE";
+
+ENDJS
+
+}
+
#--- Called from submission routine
sub processHandGrade {
- my ($request) = shift;
- my $symb = &get_symb($request);
+ my ($request,$symb) = @_;
my (undef,undef,$url) = &Apache::lonnet::decode_symb($symb);
my $button = $env{'form.gradeOpt'};
my $ngrade = $env{'form.NCT'};
@@ -2641,7 +2763,7 @@ sub processHandGrade {
if ($env{'form.withgrades'.$ctr}) {
$message.="\n\nPoint".($pts > 1 ? 's':'').' awarded = '.$pts.' out of '.$wgt;
$messagetail = " for $env{'form.probTitle'} ";
+ $feedurl."?symb=$showsymb\">$restitle";
}
$msgstatus =
&Apache::lonmsg::user_normal_msg($uname,$udom,$subject,
@@ -2669,7 +2791,7 @@ sub processHandGrade {
$udom);
if ($env{'form.withgrades'.$ctr}) {
$messagetail = " for $env{'form.probTitle'} ";
+ $baseurl."?symb=$showsymb\">$restitle";
}
$msgstatus =
&Apache::lonmsg::user_normal_msg($collaborator,$udom,$subject,$message.$messagetail,undef,$baseurl,undef,undef,undef,$showsymb,$restitle);
@@ -2681,7 +2803,8 @@ sub processHandGrade {
}
}
- if ($env{'form.handgrade'} eq 'yes') {
+# if ($env{'form.handgrade'} eq 'yes') {
+ if (1) {
# Keywords sorted in alphabatical order
my $loginuser = $env{'user.name'}.':'.$env{'user.domain'};
my %keyhash = ();
@@ -2734,22 +2857,12 @@ sub processHandGrade {
my $processUser = $env{'form.unamedom'.$ctr};
($env{'form.student'},$env{'form.userdom'}) = split(/:/,$processUser);
$env{'form.fullname'} = $$fullname{$processUser};
- &submission($request,$ctr,$total-1);
+ &submission($request,$ctr,$total-1,$symb);
$ctr++;
}
return '';
}
-# Go directly to grade student - from submission or link from chart page
- if ($button eq 'Grade Student') {
- (undef,undef,$env{'form.handgrade'},undef,undef) = &showResourceInfo($symb);
- my $processUser = $env{'form.unamedom'.$env{'form.studentNo'}};
- ($env{'form.student'},$env{'form.userdom'}) = split(/:/,$processUser);
- $env{'form.fullname'} = $$fullname{$processUser};
- &submission($request,0,0);
- return '';
- }
-
# Get the next/previous one or group of students
my $firststu = $env{'form.unamedom0'};
my $laststu = $env{'form.unamedom'.($ngrade-1)};
@@ -2769,6 +2882,7 @@ sub processHandGrade {
}
return $a cmp $b;
} (keys(%$fullname))) {
+# FIXME: this is fishy, looks like the button label
if ($nextflg == 1 && $button =~ /Next$/) {
push(@parsedlist,$item);
}
@@ -2779,6 +2893,7 @@ sub processHandGrade {
}
}
$ctr = 0;
+# FIXME: this is fishy, looks like the button label
@parsedlist = reverse @parsedlist if ($button eq 'Previous');
my $res_error;
my ($partlist) = &response_type($symb,\$res_error);
@@ -2831,14 +2946,11 @@ sub processHandGrade {
$env{'form.student'} = $uname;
$env{'form.userdom'} = $udom;
$env{'form.fullname'} = $$fullname{$_};
- &submission($request,$ctr,$total);
+ &submission($request,$ctr,$total,$symb);
$ctr++;
}
if ($total < 0) {
- my $the_end = ''.&mt('LON-CAPA User Message').' '."\n";
- $the_end.=''.&mt('[_1]Message:[_2] No more students for this section or class.','',' ').'
'."\n";
- $the_end.=&mt('Click on the button below to return to the grading menu.').' '."\n";
- $the_end.=&show_grading_menu_form($symb);
+ my $the_end.=''.&mt('[_1]Message:[_2] No more students for this section or class.','',' ').'
'."\n";
$request->print($the_end);
}
return '';
@@ -2997,8 +3109,8 @@ sub handback_files {
my $part_resp = join('_',@{ $part_response_id });
if (($env{'form.'.$newflg.'_'.$part_resp.'_countreturndoc'} =~ /^\d+$/) & ($new_part eq $part_id)) {
for (my $counter=1; $counter<=$env{'form.'.$newflg.'_'.$part_resp.'_countreturndoc'}; $counter++) {
- # if multiple files are uploaded names will be 'returndoc2','returndoc3'
- if ($env{'form.'.$newflg.'_'.$part_resp.'_returndoc'.$counter}) {
+ # if multiple files are uploaded names will be 'returndoc2','returndoc3'
+ if ($env{'form.'.$newflg.'_'.$part_resp.'_returndoc'.$counter}) {
my $fname=$env{'form.'.$newflg.'_'.$part_resp.'_returndoc'.$counter.'.filename'};
my ($directory,$answer_file) =
($env{'form.'.$newflg.'_'.$part_resp.'_origdoc'.$counter} =~ /^(.*?)([^\/]*)$/);
@@ -3006,9 +3118,11 @@ sub handback_files {
&file_name_version_ext($answer_file);
my ($portfolio_path) = ($directory =~ /^.+$stuname\/portfolio(.*)/);
my $getpropath = 1;
- my @dir_list = &Apache::lonnet::dirlist($portfolio_root.$portfolio_path,$domain,$stuname,$getpropath);
- my $version = &get_next_version($answer_name, $answer_ext, \@dir_list);
- # fix file name
+ my ($dir_list,$listerror) =
+ &Apache::lonnet::dirlist($portfolio_root.$portfolio_path,
+ $domain,$stuname,$getpropath);
+ my $version = &get_next_version($answer_name,$answer_ext,$dir_list);
+ # fix filename
my ($save_file_name) = (($directory.$answer_name.".$version.".$answer_ext) =~ /^.+\/${stuname}\/(.*)/);
my $result=&Apache::lonnet::finishuserfileupload($stuname,$domain,
$newflg.'_'.$part_resp.'_returndoc'.$counter,
@@ -3025,10 +3139,9 @@ sub handback_files {
$$newrecord{"resource.$new_part.$resp_id.handback"}.=',';
}
$$newrecord{"resource.$new_part.$resp_id.handback"} .= $save_file_name;
- $file_msg.=''.$save_file_name." ";
-
+ $file_msg.= ''.$save_file_name." ";
}
- $request->print(' '.&mt('[_1] will be the uploaded file name [_2]',''.$fname.' ',''.$env{'form.'.$newflg.'_'.$part_resp.'_origdoc'.$counter}.' '));
+ $request->print(' '.&mt('[_1] will be the uploaded filename [_2]',''.$fname.' ',''.$env{'form.'.$newflg.'_'.$part_resp.'_origdoc'.$counter}.' '));
}
}
}
@@ -3037,10 +3150,11 @@ sub handback_files {
$request->print(' ');
my @what = ($symb,$env{'request.course.id'},'handback');
&Apache::lonnet::mark_as_readonly($domain,$stuname,\@handedback,\@what);
- my $user_lh = &Apache::loncommon::user_lang($stuname,$domain,$env{'request.course.id'});
+ my $user_lh = &Apache::loncommon::user_lang($stuname,$domain,$env{'request.course.id'});
my ($subject,$message);
if (scalar(@handedback) == 1) {
$subject = &mt_user($user_lh,'File Handed Back by Instructor');
+ $message = &mt_user($user_lh,'A file has been returned that was originally submitted in response to: ');
} else {
$subject = &mt_user($user_lh,'Files Handed Back by Instructor');
$message = &mt_user($user_lh,'Files have been returned that were originally submitted in response to: ');
@@ -3168,8 +3282,10 @@ sub version_portfiles {
my ($answer_name,$answer_ver,$answer_ext) =
&file_name_version_ext($answer_file);
my $getpropath = 1;
- my @dir_list = &Apache::lonnet::dirlist($portfolio_root.$directory,$domain,$stu_name,$getpropath);
- my $version = &get_next_version($answer_name, $answer_ext, \@dir_list);
+ my ($dir_list,$listerror) =
+ &Apache::lonnet::dirlist($portfolio_root.$directory,$domain,
+ $stu_name,$getpropath);
+ my $version = &get_next_version($answer_name,$answer_ext,$dir_list);
my $new_answer = &version_selected_portfile($domain, $stu_name, $directory, $answer_file, $version);
if ($new_answer ne 'problem getting file') {
push(@versioned_portfiles, $directory.$new_answer);
@@ -3188,21 +3304,24 @@ sub version_portfiles {
sub get_next_version {
my ($answer_name, $answer_ext, $dir_list) = @_;
my $version;
- foreach my $row (@$dir_list) {
- my ($file) = split(/\&/,$row,2);
- my ($file_name,$file_version,$file_ext) =
- &file_name_version_ext($file);
- if (($file_name eq $answer_name) &&
- ($file_ext eq $answer_ext)) {
- # gets here if filename and extension match, regardless of version
+ if (ref($dir_list) eq 'ARRAY') {
+ foreach my $row (@{$dir_list}) {
+ my ($file) = split(/\&/,$row,2);
+ my ($file_name,$file_version,$file_ext) =
+ &file_name_version_ext($file);
+ if (($file_name eq $answer_name) &&
+ ($file_ext eq $answer_ext)) {
+ # gets here if filename and extension match,
+ # regardless of version
if ($file_version ne '') {
- # a versioned file is found so save it for later
- if ($file_version > $version) {
- $version = $file_version;
- }
+ # a versioned file is found so save it for later
+ if ($file_version > $version) {
+ $version = $file_version;
+ }
+ }
}
}
- }
+ }
$version ++;
return($version);
}
@@ -3249,8 +3368,7 @@ sub viewgrades_js {
my ($request) = shift;
my $alertmsg = &mt('A number equal or greater than 0 is expected. Entered value = ');
- $request->print(<
+ $request->print(&Apache::lonhtmlcommon::scripttag(<
VIEWJAVASCRIPT
}
#--- show scores for a section or whole class w/ option to change/update a score
sub viewgrades {
- my ($request) = shift;
+ my ($request,$symb) = @_;
&viewgrades_js($request);
- my ($symb) = &get_symb($request);
#need to make sure we have the correct data for later EXT calls,
#thus invalidate the cache
&Apache::lonnet::devalidatecourseresdata(
@@ -3429,7 +3545,6 @@ sub viewgrades {
&Apache::lonnet::clear_EXT_cache_status();
my $result=''.&mt('Manual Grading').' ';
- $result.=''.&mt('Current Resource: [_1]',$env{'form.probTitle'}).' '."\n";
#view individual student submission form - called using Javascript viewOneStudent
$result.=&jscriptNform($symb);
@@ -3440,9 +3555,7 @@ sub viewgrades {
' '."\n".
' '."\n".
&build_section_inputs().
- ' '."\n".
' '."\n".
- ' '."\n";
my ($common_header,$specific_header);
if ($env{'form.section'} eq 'all') {
@@ -3492,9 +3605,10 @@ sub viewgrades {
$partid.'" size="4" '.'onchange="javascript:writePoint(\''.
$partid.'\','.$weight{$partid}.',\'textval\')" /> /'.
$weight{$partid}.' '.&mt('(problem weight)').' '."\n";
- $line.= ''.&mt('Grade Status').': '.
+ $line.= ''.&mt('Grade Status').': '.
+ ' '.
' '.
''.&mt('excused').' '.
''.&mt('reset status').' '.
@@ -3537,11 +3651,14 @@ sub viewgrades {
if (!$display) { $display = &Apache::lonnet::metadata($url,$part.'.name'); }
my ($partid) = &split_part_type($part);
push(@partids,$partid);
+#
+# FIXME: Looks like $display looks at English text
+#
my $display_part=&get_display_part($partid,$symb);
if ($display =~ /^Partial Credit Factor/) {
$result.=''.
- &mt('Score Part: [_1] (weight = [_2])',
- $display_part,$weight{$partid}).' '."\n";
+ &mt('Score Part: [_1][_2](weight = [_3])',
+ $display_part,' ',$weight{$partid}).''."\n";
next;
} else {
@@ -3588,7 +3705,6 @@ sub viewgrades {
$section_display, $stu_status).
'';
}
- $result.=&show_grading_menu_form($symb);
return $result;
}
@@ -3660,12 +3776,10 @@ sub viewstudentgrade {
#--- change scores for all the students in a section/class
# record does not get update if unchanged
sub editgrades {
- my ($request) = @_;
+ my ($request,$symb) = @_;
- my $symb=&get_symb($request);
my $section_display = join (", ",&Apache::loncommon::get_env_multiple('form.section'));
my $title=''.&mt('Current Grade Status').' ';
- $title.=''.&mt('Current Resource: [_1]',$env{'form.probTitle'}).' '."\n";
$title.=''.&mt('Section: [_1]',$section_display).' '."\n";
my $result= &Apache::loncommon::start_data_table().
@@ -3873,8 +3987,7 @@ sub editgrades {
&Apache::loncommon::end_data_table_row();
}
}
- $result .= &Apache::loncommon::end_data_table().
- &show_grading_menu_form($symb);
+ $result .= &Apache::loncommon::end_data_table();
my $msg = ''.
&mt('Number of records updated = [_1] for [quant,_2,student].',
$rec_update,$count).' '.
@@ -3987,21 +4100,14 @@ sub csvuploadmap_header {
$javascript=&csvupload_javascript_forward_associate();
}
- my ($result) = &showResourceInfo($symb,$env{'form.probTitle'});
- my $checked=(($env{'form.noFirstLine'})?' checked="checked"':'');
- my $ignore=&mt('Ignore First Line');
$symb = &Apache::lonenc::check_encrypt($symb);
+ $request->print('
'.
+ &mt('Total number of records found in file: [_1]',$distotal).' '.
+ &mt('Associate entries from the uploaded file with as many fields as you can.'));
+ my $reverse=&mt("Reverse Association");
$request->print(<
-Uploading Class Grades
-$result
-
-Identify fields
-Total number of records found in file: $distotal
-Enter as many fields as you can. The system will inform you and bring you back
-to this page if the data selected is insufficient to run your class.
-
- $ignore
+
+
@@ -4010,14 +4116,10 @@ to this page if the data selected is ins
-
-
-
ENDPICK
+ $request->print(&Apache::lonhtmlcommon::scripttag($javascript));
return '';
}
@@ -4051,19 +4153,19 @@ sub csvupload_fields {
sub csvuploadmap_footer {
my ($request,$i,$keyfields) =@_;
+ my $buttontext = &mt('Assign Grades');
$request->print(<
-
+
ENDPICK
}
sub checkforfile_js {
my $alertmsg = &mt('Please use the browse button to select a file from your local directory.');
- my $result =<
+ my $result = &Apache::lonhtmlcommon::scripttag(<
CSVFORMJS
return $result;
}
sub upcsvScores_form {
- my ($request) = shift;
- my ($symb)=&get_symb($request);
+ my ($request,$symb) = @_;
if (!$symb) {return '';}
my $result=&checkforfile_js();
- $env{'form.probTitle'} = &Apache::lonnet::gettitle($symb);
- my ($table) = &showResourceInfo($symb,$env{'form.probTitle'});
- $result.=$table;
- $result.=''."\n";
- $result.=''."\n";
- $result.='
'."\n";
- $result.=&show_grading_menu_form($symb);
+ &mt("How do I create a CSV file from a spreadsheet")).
+ ' '.
+ &Apache::loncommon::end_data_table_row().
+ &Apache::loncommon::end_data_table();
return $result;
}
sub csvuploadmap {
- my ($request)= @_;
- my ($symb)=&get_symb($request);
+ my ($request,$symb)= @_;
if (!$symb) {return '';}
my $datatoken;
@@ -4126,7 +4219,6 @@ sub csvuploadmap {
&Apache::loncommon::load_tmp_file($request);
}
my @records=&Apache::loncommon::upfile_record_sep();
- if ($env{'form.noFirstLine'}) { shift(@records); }
&csvuploadmap_header($request,$symb,$datatoken,$#records+1);
my ($i,$keyfields);
if (@records) {
@@ -4156,39 +4248,27 @@ sub csvuploadmap {
}
}
&csvuploadmap_footer($request,$i,$keyfields);
- $request->print(&show_grading_menu_form($symb));
return '';
}
sub csvuploadoptions {
- my ($request)= @_;
- my ($symb)=&get_symb($request);
- my $checked=(($env{'form.noFirstLine'})?'1':'0');
- my $ignore=&mt('Ignore First Line');
+ my ($request,$symb)= @_;
+ my $overwrite=&mt('Overwrite any existing score');
$request->print(<
-Uploading Class Grade Options
-
- Overwrite any existing score
+ $overwrite
ENDPICK
my %fields=&get_fields();
if (!defined($fields{'domain'})) {
my $domform = &Apache::loncommon::select_dom_form($env{'request.role.domain'},'default_domain');
- $request->print("\n Users are in domain: ".$domform."
\n");
+ $request->print("\n".&mt('Users are in domain: [_1]',$domform)."
\n");
}
foreach my $key (sort(keys(%env))) {
if ($key !~ /^form\.(.*)$/) { next; }
@@ -4199,9 +4279,8 @@ ENDPICK
}
# FIXME do a check for any duplicated user ids...
# FIXME do a check for any invalid user ids?...
- $request->print('
+ $request->print('
'."\n");
- $request->print(&show_grading_menu_form($symb));
return '';
}
@@ -4223,15 +4302,12 @@ sub get_fields {
}
sub csvuploadassign {
- my ($request)= @_;
- my ($symb)=&get_symb($request);
+ my ($request,$symb)= @_;
if (!$symb) {return '';}
my $error_msg = '';
&Apache::loncommon::load_tmp_file($request);
my @gradedata = &Apache::loncommon::upfile_record_sep();
- if ($env{'form.noFirstLine'}) { shift(@gradedata); }
my %fields=&get_fields();
- $request->print('Assigning Grades ');
my $courseid=$env{'request.course.id'};
my ($classlist) = &getclasslist('all',0);
my @notallowed;
@@ -4286,7 +4362,7 @@ sub csvuploadassign {
my $award=($pcr == 0) ? 'incorrect_by_override'
: 'correct_by_override';
if ($pcr>1) {
- push(@warnings,&mt("[_1]: point value larger than weight","$username:$domain"));
+ push(@warnings,&mt("[_1]: point value larger than weight","$username:$domain"));
}
$grades{"resource.$part.awarded"}=$pcr;
$grades{"resource.$part.solved"}=$award;
@@ -4315,19 +4391,20 @@ sub csvuploadassign {
$env{'request.course.id'},
$domain,$username);
if ($result eq 'ok') {
+# Successfully stored
$request->print('.');
# Remove from grading queue
&Apache::bridgetask::remove_from_queue('gradingqueue',$symb,
$env{'course.'.$env{'request.course.id'}.'.domain'},
$env{'course.'.$env{'request.course.id'}.'.num'},
$domain,$username);
- } else {
+ $countdone++;
+ } else {
$request->print("".
&mt("Failed to save data for student [_1]. Message when trying to save was: [_2]",
"$username:$domain",$result)."
");
}
$request->rflush();
- $countdone++;
}
}
$request->print(' '.&Apache::lonhtmlcommon::confirm_success(&mt("Saved scores for [quant,_1,student]",$countdone),$countdone==0));
@@ -4344,7 +4421,6 @@ sub csvuploadassign {
$request->print(join(', ',@notallowed));
}
$request->print(" \n");
- $request->print(&show_grading_menu_form($symb));
return $error_msg;
}
#------------- end of section for handling csv file upload ---------
@@ -4355,11 +4431,10 @@ sub csvuploadassign {
#
#--- Select a page/sequence and a student to grade
sub pickStudentPage {
- my ($request) = shift;
+ my ($request,$symb) = @_;
my $alertmsg = &mt('Please select the student you wish to grade.');
- $request->print(<
+ $request->print(&Apache::lonhtmlcommon::scripttag(<
LISTJAVASCRIPT
&commonJSfunctions($request);
- my ($symb) = &get_symb($request);
+
my $cdom = $env{"course.$env{'request.course.id'}.domain"};
my $cnum = $env{"course.$env{'request.course.id'}.num"};
my $getsec = $env{'form.section'} eq '' ? 'all' : $env{'form.section'};
@@ -4393,49 +4467,68 @@ LISTJAVASCRIPT
my ($curpage) =&Apache::lonnet::decode_symb($symb);
# my ($curpage,$mapId) =&Apache::lonnet::decode_symb($symb);
# my $type=($curpage =~ /\.(page|sequence)/);
- my $select = ''."\n";
+
+ # Collection of hidden fields
my $ctr=0;
foreach (@$titles) {
- my ($minder,$showtitle) = ($_ =~ /(\d+)\.(.*)/);
- $select.=''.$showtitle.' '."\n";
- $ctr++;
+ my ($minder,$showtitle) = ($_ =~ /(\d+)\.(.*)/);
+ $result.=' '."\n";
+ $result.=' '."\n";
+ $ctr++;
}
- $select.= ' ';
- $result.=' '.&mt('Problems from').': '.$select." \n";
+ $result.=' '."\n".
+ ' '."\n";
+
+ $result.=&build_section_inputs();
+ my $stu_status = join(':',&Apache::loncommon::get_env_multiple('form.Status'));
+ $result.=' '."\n".
+ ' '."\n".
+ ' '."\n";
+ # Show grading options
+ $result.=&Apache::lonhtmlcommon::start_pick_box();
+ my $select = ''."\n";
$ctr=0;
foreach (@$titles) {
my ($minder,$showtitle) = ($_ =~ /(\d+)\.(.*)/);
- $result.=' '."\n";
- $result.=' '."\n";
+ $select.=''.$showtitle.' '."\n";
$ctr++;
}
- $result.=' '."\n".
- ' '."\n";
+ $select.= ' ';
- my $options =
- ' '.&mt('no').' '."\n".
- ' '.&mt('yes').' '." \n";
- $result.=' '.&mt('View Problem Text').': '.$options;
-
- $options =
- ' '.&mt('none').' '."\n".
- ' '.&mt('by dates and submissions').' '."\n".
- ' '.&mt('all details').' '."\n";
- $result.=' '.&mt('Submissions').': '.$options;
+ $result.=
+ &Apache::lonhtmlcommon::row_title(&mt('Problems from'))
+ .$select
+ .&Apache::lonhtmlcommon::row_closure();
+
+ $result.=
+ &Apache::lonhtmlcommon::row_title(&mt('View Problem Text'))
+ .' '.&mt('no').' '."\n"
+ .' '
+ .&mt('yes').' '."\n"
+ .&Apache::lonhtmlcommon::row_closure();
+
+ $result.=
+ &Apache::lonhtmlcommon::row_title(&mt('View Submissions'))
+ .' '
+ .&mt('none').' '."\n"
+ .' '.&mt('all submissions').' '."\n"
+ .' '
+ .&mt('all submissions with details').' '
+ .&Apache::lonhtmlcommon::row_closure();
- $result.=&build_section_inputs();
- my $stu_status = join(':',&Apache::loncommon::get_env_multiple('form.Status'));
- $result.=' '."\n".
- ' '."\n".
- ' '."\n".
- ' '." \n";
-
- $result.=' '.&mt('Use CODE').': '."\n";
+ $result.=
+ &Apache::lonhtmlcommon::row_title(&mt('Use CODE'))
+ .' '
+ .&Apache::lonhtmlcommon::row_closure(1)
+ .&Apache::lonhtmlcommon::end_pick_box();
- $result.=' '."\n";
$request->print($result);
@@ -4477,7 +4570,6 @@ LISTJAVASCRIPT
$studentTable.=' '."\n";
- $studentTable.=&show_grading_menu_form($symb);
$request->print($studentTable);
return '';
@@ -4514,9 +4606,7 @@ sub getSymbMap {
#
#--- Displays a page/sequence w/wo problems, w/wo submissions
sub displayPage {
- my ($request) = shift;
-
- my ($symb) = &get_symb($request);
+ my ($request,$symb) = @_;
my $cdom = $env{"course.$env{'request.course.id'}.domain"};
my $cnum = $env{"course.$env{'request.course.id'}.num"};
my $getsec = $env{'form.section'} eq '' ? 'all' : $env{'form.section'};
@@ -4533,9 +4623,12 @@ sub displayPage {
&Apache::lonnet::clear_EXT_cache_status();
if (!&canview($usec)) {
- $request->print(''.&mt('Unable to view requested student. ([_1])',$env{'form.student'}).' ');
- $request->print(&show_grading_menu_form($symb));
- return;
+ $request->print(
+ ''.
+ &mt('Unable to view requested student. ([_1])',
+ $env{'form.student'}).
+ ' ');
+ return;
}
my $result=' '.$env{'form.title'}.' ';
$result.=' '.&mt('Student: [_1]',&nameUserString(undef,$$fullname{$env{'form.student'}},$uname,$udom)).
@@ -4552,14 +4645,12 @@ sub displayPage {
my $navmap = Apache::lonnavmaps::navmap->new();
unless (ref($navmap)) {
$request->print(&navmap_errormsg());
- $request->print(&show_grading_menu_form($symb));
return;
}
my ($mapUrl, $id, $resUrl)=&Apache::lonnet::decode_symb($env{'form.page'});
my $map = $navmap->getResourceByUrl($resUrl); # add to navmaps
if (!$map) {
$request->print(''.&mt('Unable to view requested sequence. ([_1])',$resUrl).' ');
- $request->print(&show_grading_menu_form($symb));
return;
}
my $iterator = $navmap->getIterator($map->map_start(),
@@ -4572,8 +4663,7 @@ sub displayPage {
' '."\n".
' '."\n".
' '."\n".
- ' '."\n".
- ' '."\n";
+ ' '."\n";
if (defined($env{'form.CODE'})) {
$studentTable.=
@@ -4587,7 +4677,7 @@ sub displayPage {
''."\n".
&Apache::loncommon::start_data_table().
&Apache::loncommon::start_data_table_header_row().
- ' Prob. '.
+ ''.&mt('Prob.').' '.
' '.($env{'form.vProb'} eq 'no' ? &mt('Title') : &mt('Problem Text')).'/'.&mt('Grade').' '.
&Apache::loncommon::end_data_table_header_row();
@@ -4607,8 +4697,8 @@ sub displayPage {
&Apache::loncommon::start_data_table_row().
''.$prob.
(scalar(@{$parts}) == 1 ? ''
- : ' ('.&mt('[_1]parts)',
- scalar(@{$parts}).' ')
+ : ' ('.&mt('[_1]parts',
+ scalar(@{$parts}).' ').')'
).
' ';
$studentTable.='';
@@ -4675,7 +4765,6 @@ sub displayPage {
' '.
''."\n";
- $studentTable.=&show_grading_menu_form($symb);
$request->print($studentTable);
return '';
@@ -4690,6 +4779,7 @@ sub displaySubByDates {
&Apache::loncommon::start_data_table_header_row().
' '.&mt('Date/Time').' '.
($isCODE?''.&mt('CODE').' ':'').
+ ($isTask?''.&mt('Version').' ':'').
''.&mt('Submission').' '.
''.&mt('Status').' '.
&Apache::loncommon::end_data_table_header_row();
@@ -4710,7 +4800,9 @@ sub displaySubByDates {
if (exists($$record{$version.':resource.0.version'})) {
$interaction = $$record{$version.':resource.0.version'};
}
-
+ if ($isTask && $env{'form.previousversion'}) {
+ next unless ($interaction == $env{'form.previousversion'});
+ }
my $where = ($isTask ? "$version:resource.$interaction"
: "$version:resource");
$studentTable.=&Apache::loncommon::start_data_table_row().
@@ -4718,6 +4810,9 @@ sub displaySubByDates {
if ($isCODE) {
$studentTable.=''.$record->{$version.':resource.CODE'}.' ';
}
+ if ($isTask) {
+ $studentTable.=''.$interaction.' ';
+ }
my @versionKeys = split(/\:/,$$record{$version.':keys'});
my @displaySub = ();
foreach my $partid (@{$parts}) {
@@ -4737,7 +4832,7 @@ sub displaySubByDates {
my ($responseId)= ($isTask ? ($matchKey=~ /^resource\.(.*?)\.\Q$partid\E\.award$/)
: ($matchKey=~ /^resource\.\Q$partid\E\.(.*?)\.submission$/));
- $displaySub[0].='';
$displaySub[0].=''.&mt('Part: [_1]',$display_part).' '
.' '
.'('.&mt('Response ID: [_1]',$responseId).')'
@@ -4761,6 +4856,7 @@ sub displaySubByDates {
$newvariation = ' ('.&mt('New variation this try').')';
}
}
+ $lastrndseed{$partid} = $rndseed;
}
my $responseType=($isTask ? 'Task'
: $responseType->{$partid}->{$responseId});
@@ -4813,7 +4909,7 @@ sub displaySubByDates {
}
sub updateGradeByPage {
- my ($request) = shift;
+ my ($request,$symb) = @_;
my $cdom = $env{"course.$env{'request.course.id'}.domain"};
my $cnum = $env{"course.$env{'request.course.id'}.num"};
@@ -4824,7 +4920,6 @@ sub updateGradeByPage {
my $usec=$classlist->{$env{'form.student'}}[5];
if (!&canmodify($usec)) {
$request->print(''.&mt('Unable to modify requested student ([_1])',$env{'form.student'}).' ');
- $request->print(&show_grading_menu_form($env{'form.symb'}));
return;
}
my $result=' '.$env{'form.title'}.' ';
@@ -4843,8 +4938,6 @@ sub updateGradeByPage {
my $map = $navmap->getResourceByUrl($resUrl); # add to navmaps
if (!$map) {
$request->print(''.&mt('Unable to grade requested sequence ([_1]).',$resUrl).' ');
- my ($symb)=&get_symb($request);
- $request->print(&show_grading_menu_form($symb));
return;
}
my $iterator = $navmap->getIterator($map->map_start(),
@@ -4970,7 +5063,6 @@ sub updateGradeByPage {
}
$studentTable.=&Apache::loncommon::end_data_table();
- $studentTable.=&show_grading_menu_form($env{'form.symb'});
my $grademsg=($changeflag == 0 ? &mt('No score was changed or updated.') :
&mt('The scores were changed for [quant,_1,problem].',
$changeflag));
@@ -5009,7 +5101,7 @@ like.
Next each scanline is checked for any errors of either 'missing
bubbles' (it's an error because it may have been mis-scanned
because too light bubbling), 'double bubble' (each bubble line should
-have no more that one letter picked), invalid or duplicated CODE,
+have no more than one letter picked), invalid or duplicated CODE,
invalid student/employee ID
If the CODE option is used that determines the randomization of the
@@ -5048,9 +5140,7 @@ the homework problem.
sub defaultFormData {
my ($symb)=@_;
- return ' '."\n".
- ' '."\n".
- ' '."\n";
+ return ' ';
}
@@ -5099,6 +5189,11 @@ my %subdivided_bubble_lines; # no.
my %responsetype_per_response; # responsetype for each response
+my %masterseq_id_responsenum; # src_id (e.g., 12.3_0.11 etc.) for each
+ # numbered response. Needed when randomorder
+ # or randompick are in use. Key is ID, value
+ # is response number.
+
# Save and restore the bubble lines array to the form env.
@@ -5112,12 +5207,17 @@ sub save_bubble_lines {
$env{"form.scantron.responsetype.$line"} =
$responsetype_per_response{$line};
}
+ foreach my $resid (keys(%masterseq_id_responsenum)) {
+ my $line = $masterseq_id_responsenum{$resid};
+ $env{"form.scantron.residpart.$line"} = $resid;
+ }
}
sub restore_bubble_lines {
my $line = 0;
%bubble_lines_per_response = ();
+ %masterseq_id_responsenum = ();
while ($env{"form.scantron.bubblelines.$line"}) {
my $value = $env{"form.scantron.bubblelines.$line"};
$bubble_lines_per_response{$line} = $value;
@@ -5127,28 +5227,12 @@ sub restore_bubble_lines {
$env{"form.scantron.sub_bubblelines.$line"};
$responsetype_per_response{$line} =
$env{"form.scantron.responsetype.$line"};
+ my $id = $env{"form.scantron.residpart.$line"};
+ $masterseq_id_responsenum{$id} = $line;
$line++;
}
}
-# Given the parsed scanline, get the response for
-# 'answer' number n:
-
-sub get_response_bubbles {
- my ($parsed_line, $response) = @_;
-
- my $bubble_line = $first_bubble_line{$response-1} +1;
- my $bubble_lines= $bubble_lines_per_response{$response-1};
-
- my $selected = "";
-
- for (my $bline = 0; $bline < $bubble_lines; $bline++) {
- $selected .= $$parsed_line{"scantron.$bubble_line.answer"}.":";
- $bubble_line++;
- }
- return $selected;
-}
-
=pod
=item scantron_filenames
@@ -5161,14 +5245,16 @@ sub scantron_filenames {
my $cdom=$env{'course.'.$env{'request.course.id'}.'.domain'};
my $cname=$env{'course.'.$env{'request.course.id'}.'.num'};
my $getpropath = 1;
- my @files=&Apache::lonnet::dirlist('userfiles',$cdom,$cname,
- $getpropath);
+ my ($dirlist,$listerror) = &Apache::lonnet::dirlist('userfiles',$cdom,
+ $cname,$getpropath);
my @possiblenames;
- foreach my $filename (sort(@files)) {
- ($filename)=split(/&/,$filename);
- if ($filename!~/^scantron_orig_/) { next ; }
- $filename=~s/^scantron_orig_//;
- push(@possiblenames,$filename);
+ if (ref($dirlist) eq 'ARRAY') {
+ foreach my $filename (sort(@{$dirlist})) {
+ ($filename)=split(/&/,$filename);
+ if ($filename!~/^scantron_orig_/) { next ; }
+ $filename=~s/^scantron_orig_//;
+ push(@possiblenames,$filename);
+ }
}
return @possiblenames;
}
@@ -5336,8 +5422,7 @@ sub scantron_CODEunique {
=cut
sub scantron_selectphase {
- my ($r,$file2grade) = @_;
- my ($symb)=&get_symb($r);
+ my ($r,$file2grade,$symb) = @_;
if (!$symb) {return '';}
my $map_error;
my $sequence_selector=&getSequenceDropDown($symb,\$map_error);
@@ -5346,7 +5431,6 @@ sub scantron_selectphase {
return;
}
my $default_form_data=&defaultFormData($symb);
- my $grading_menu_button=&show_grading_menu_form($symb);
my $file_selector=&scantron_uploads($file2grade);
my $format_selector=&scantron_scantab();
my $CODE_selector=&scantron_CODElist();
@@ -5358,7 +5442,7 @@ sub scantron_selectphase {
if (&Apache::lonnet::allowed('usc',$env{'request.role.domain'}) ||
&Apache::lonnet::allowed('usc',$env{'request.course.id'})) {
- # Chunk of form to prompt for a scantron file upload.
+ # Chunk of form to prompt for a scantron file upload.
$r->print('
@@ -5371,20 +5455,18 @@ sub scantron_selectphase {
'.&Apache::loncommon::start_data_table_row().'
');
- my $default_form_data=&defaultFormData(&get_symb($r,1));
+ my $default_form_data=&defaultFormData($symb);
my $cdom= $env{'course.'.$env{'request.course.id'}.'.domain'};
my $cnum= $env{'course.'.$env{'request.course.id'}.'.num'};
- $r->print('
-
-
+ if (formname.upfile.value == "") {
+ alert("'.&mt('Please use the browse button to select a file from your local directory.').'");
+ return false;
+ }
+ formname.submit();
+ }'));
+ $r->print('
'.$default_form_data.'
@@ -5450,6 +5532,8 @@ sub scantron_selectphase {
$r->print($result);
+
+
# Chunk of the form that prompts to view a scoring office file,
# corrected file, skipped records in a file.
@@ -5476,7 +5560,7 @@ sub scantron_selectphase {
&Apache::lonpickcode::code_list($r,2);
- $r->print(' '.
+ $r->print(' '.
$default_form_data."\n".
&Apache::loncommon::start_data_table('LC_scantron_action')."\n".
&Apache::loncommon::start_data_table_header_row()."\n".
@@ -5508,7 +5592,6 @@ sub scantron_selectphase {
&Apache::loncommon::end_data_table_row()."\n".
&Apache::loncommon::end_data_table()."\n".
' ');
- $r->print($grading_menu_button);
return;
}
@@ -5516,7 +5599,7 @@ sub scantron_selectphase {
=item get_scantron_config
- Parse and return the scantron configuration line selected as a
+ Parse and return the bubblesheet configuration line selected as a
hash of configuration file fields.
Arguments:
@@ -5566,7 +5649,7 @@ sub scantron_selectphase {
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
+ BubblesPerRow - number of bubbles available in each row used to
bubble an answer. (If not specified, 10 assumed).
=cut
@@ -5800,16 +5883,37 @@ sub digits_to_letters {
=item scantron_parse_scanline
- Decodes a scanline from the selected scantron file
+ Decodes a scanline from the selected bubblesheet file
Arguments:
- line - The text of the scantron file line to process
+ line - The text of the bubblesheet file line to process
whichline - Line number
- scantron_config - Hash describing the format of the scantron lines.
+ scantron_config - Hash describing the format of the bubblesheet lines.
scan_data - Hash of extra information about the scanline
(see scantron_getfile for more information)
just_header - True if should not process question answers but only
the stuff to the left of the answers.
+ randomorder - True if randomorder in use
+ randompick - True if randompick in use
+ sequence - Exam folder URL
+ master_seq - Ref to array containing symbs in exam folder
+ symb_to_resource - Ref to hash of symbs for resources in exam folder
+ (corresponding values are resource objects)
+ partids_by_symb - Ref to hash of symb -> array ref of partIDs
+ orderedforcode - Ref to hash of arrays. keys are CODEs and values
+ are refs to an array of resource objects, ordered
+ according to order used for CODE, when randomorder
+ and or randompick are in use.
+ respnumlookup - Ref to hash mapping question numbers in bubble lines
+ for current line to question number used for same question
+ in "Master Sequence" (as seen by Course Coordinator).
+ startline - Ref to hash where key is question number (0 is first)
+ and value is number of first bubble line for current
+ student or code-based randompick and/or randomorder.
+ totalref - Ref of scalar used to score total number of bubble
+ lines needed for responses in a scan line (used when
+ randompick in use.
+
Returns:
Hash containing the result of parsing the scanline
@@ -5854,12 +5958,12 @@ sub digits_to_letters {
=cut
sub scantron_parse_scanline {
- my ($line,$whichline,$scantron_config,$scan_data,$just_header)=@_;
+ my ($line,$whichline,$scantron_config,$scan_data,$just_header,$idmap,
+ $randomorder,$randompick,$sequence,$master_seq,$symb_to_resource,
+ $partids_by_symb,$orderedforcode,$respnumlookup,$startline,$totalref)=@_;
my %record;
- my $lastpos = $env{'form.scantron_maxbubble'}*$$scantron_config{'Qlength'};
- my $questions=substr($line,$$scantron_config{'Qstart'}-1,$lastpos); # Answers
- my $data=substr($line,0,$$scantron_config{'Qstart'}-1); # earlier stuff
+ my $data=substr($line,0,$$scantron_config{'Qstart'}-1); # stuff before answers
if (!($$scantron_config{'CODElocation'} eq 0 ||
$$scantron_config{'CODElocation'} eq 'none')) {
if ($$scantron_config{'CODElocation'} < 0 ||
@@ -5895,10 +5999,29 @@ sub scantron_parse_scanline {
my $questnum=0;
my $ansnum =1; # Multiple 'answer lines'/question.
+ my $lastpos = $env{'form.scantron_maxbubble'}*$$scantron_config{'Qlength'};
+ if ($randompick || $randomorder) {
+ my $total = &get_respnum_lookups($sequence,$scan_data,$idmap,$line,\%record,
+ $master_seq,$symb_to_resource,
+ $partids_by_symb,$orderedforcode,
+ $respnumlookup,$startline);
+ if ($total) {
+ $lastpos = $total*$$scantron_config{'Qlength'};
+ }
+ if (ref($totalref)) {
+ $$totalref = $total;
+ }
+ }
+ my $questions=substr($line,$$scantron_config{'Qstart'}-1,$lastpos); # Answers
chomp($questions); # Get rid of any trailing \n.
$questions =~ s/\r$//; # Get rid of trailing \r too (MAC or Win uploads).
while (length($questions)) {
- my $answers_needed = $bubble_lines_per_response{$questnum};
+ my $answers_needed;
+ if (($randompick || $randomorder) && (ref($respnumlookup) eq 'HASH')) {
+ $answers_needed = $bubble_lines_per_response{$respnumlookup->{$questnum}};
+ } else {
+ $answers_needed = $bubble_lines_per_response{$questnum};
+ }
my $answer_length = ($$scantron_config{'Qlength'} * $answers_needed)
|| 1;
$questnum++;
@@ -5907,11 +6030,16 @@ sub scantron_parse_scanline {
$questions = substr($questions,$answer_length);
if (length($currentquest) < $answer_length) { next; }
- if ($subdivided_bubble_lines{$questnum-1} =~ /,/) {
+ my $subdivided;
+ if (($randompick || $randomorder) && (ref($respnumlookup) eq 'HASH')) {
+ $subdivided = $subdivided_bubble_lines{$respnumlookup->{$questnum-1}};
+ } else {
+ $subdivided = $subdivided_bubble_lines{$questnum-1};
+ }
+ if ($subdivided =~ /,/) {
my $subquestnum = 1;
my $subquestions = $currentquest;
- my @subanswers_needed =
- split(/,/,$subdivided_bubble_lines{$questnum-1});
+ my @subanswers_needed = split(/,/,$subdivided);
foreach my $subans (@subanswers_needed) {
my $subans_length =
($$scantron_config{'Qlength'} * $subans) || 1;
@@ -5922,10 +6050,13 @@ sub scantron_parse_scanline {
($$scantron_config{'Qon'} eq 'number')) {
$ansnum = &scantron_validator_lettnum($ansnum,
$questnum,$quest_id,$subans,$currsubquest,$whichline,
- \@alphabet,\%record,$scantron_config,$scan_data);
+ \@alphabet,\%record,$scantron_config,$scan_data,
+ $randomorder,$randompick,$respnumlookup);
} else {
$ansnum = &scantron_validator_positional($ansnum,
- $questnum,$quest_id,$subans,$currsubquest,$whichline, \@alphabet,\%record,$scantron_config,$scan_data);
+ $questnum,$quest_id,$subans,$currsubquest,$whichline,
+ \@alphabet,\%record,$scantron_config,$scan_data,
+ $randomorder,$randompick,$respnumlookup);
}
$subquestnum ++;
}
@@ -5934,11 +6065,13 @@ sub scantron_parse_scanline {
($$scantron_config{'Qon'} eq 'number')) {
$ansnum = &scantron_validator_lettnum($ansnum,$questnum,
$quest_id,$answers_needed,$currentquest,$whichline,
- \@alphabet,\%record,$scantron_config,$scan_data);
+ \@alphabet,\%record,$scantron_config,$scan_data,
+ $randomorder,$randompick,$respnumlookup);
} else {
$ansnum = &scantron_validator_positional($ansnum,$questnum,
$quest_id,$answers_needed,$currentquest,$whichline,
- \@alphabet,\%record,$scantron_config,$scan_data);
+ \@alphabet,\%record,$scantron_config,$scan_data,
+ $randomorder,$randompick,$respnumlookup);
}
}
}
@@ -5946,9 +6079,66 @@ sub scantron_parse_scanline {
return \%record;
}
+sub get_master_seq {
+ my ($resources,$master_seq,$symb_to_resource) = @_;
+ return unless ((ref($resources) eq 'ARRAY') && (ref($master_seq) eq 'ARRAY') &&
+ (ref($symb_to_resource) eq 'HASH'));
+ my $resource_error;
+ foreach my $resource (@{$resources}) {
+ my $ressymb;
+ if (ref($resource)) {
+ $ressymb = $resource->symb();
+ push(@{$master_seq},$ressymb);
+ $symb_to_resource->{$ressymb} = $resource;
+ } else {
+ $resource_error = 1;
+ last;
+ }
+ }
+ return $resource_error;
+}
+
+sub get_respnum_lookups {
+ my ($sequence,$scan_data,$idmap,$line,$record,$master_seq,$symb_to_resource,
+ $partids_by_symb,$orderedforcode,$respnumlookup,$startline) = @_;
+ return unless ((ref($record) eq 'HASH') && (ref($master_seq) eq 'ARRAY') &&
+ (ref($symb_to_resource) eq 'HASH') && (ref($partids_by_symb) eq 'HASH') &&
+ (ref($orderedforcode) eq 'HASH') && (ref($respnumlookup) eq 'HASH') &&
+ (ref($startline) eq 'HASH'));
+ my ($user,$scancode);
+ if ((exists($record->{'scantron.CODE'})) &&
+ (&Apache::lonnet::validCODE($record->{'scantron.CODE'}))) {
+ $scancode = $record->{'scantron.CODE'};
+ } else {
+ $user = &scantron_find_student($record,$scan_data,$idmap,$line);
+ }
+ my @mapresources =
+ &users_order($user,$scancode,$sequence,$master_seq,$symb_to_resource,
+ $orderedforcode);
+ my $total = 0;
+ my $count = 0;
+ foreach my $resource (@mapresources) {
+ my $id = $resource->id();
+ my $symb = $resource->symb();
+ if (ref($partids_by_symb->{$symb}) eq 'ARRAY') {
+ foreach my $partid (@{$partids_by_symb->{$symb}}) {
+ my $respnum = $masterseq_id_responsenum{$id.'_'.$partid};
+ if ($respnum ne '') {
+ $respnumlookup->{$count} = $respnum;
+ $startline->{$count} = $total;
+ $total += $bubble_lines_per_response{$respnum};
+ $count ++;
+ }
+ }
+ }
+ }
+ return $total;
+}
+
sub scantron_validator_lettnum {
my ($ansnum,$questnum,$quest_id,$answers_needed,$currquest,$whichline,
- $alphabet,$record,$scantron_config,$scan_data) = @_;
+ $alphabet,$record,$scantron_config,$scan_data,$randomorder,
+ $randompick,$respnumlookup) = @_;
# Qon 'letter' implies for each slot in currquest we have:
# ? or * for doubles, a letter in A-Z for a bubble, and
@@ -5967,19 +6157,23 @@ sub scantron_validator_lettnum {
$matchon = '\d';
}
my $occurrences = 0;
- if (($responsetype_per_response{$questnum-1} eq 'essayresponse') ||
- ($responsetype_per_response{$questnum-1} eq 'formularesponse') ||
- ($responsetype_per_response{$questnum-1} eq 'stringresponse') ||
- ($responsetype_per_response{$questnum-1} eq 'imageresponse') ||
- ($responsetype_per_response{$questnum-1} eq 'reactionresponse') ||
- ($responsetype_per_response{$questnum-1} eq 'organicresponse')) {
+ my $responsenum = $questnum-1;
+ if (($randompick || $randomorder) && (ref($respnumlookup) eq 'HASH')) {
+ $responsenum = $respnumlookup->{$questnum-1}
+ }
+ if (($responsetype_per_response{$responsenum} eq 'essayresponse') ||
+ ($responsetype_per_response{$responsenum} eq 'formularesponse') ||
+ ($responsetype_per_response{$responsenum} eq 'stringresponse') ||
+ ($responsetype_per_response{$responsenum} eq 'imageresponse') ||
+ ($responsetype_per_response{$responsenum} eq 'reactionresponse') ||
+ ($responsetype_per_response{$responsenum} eq 'organicresponse')) {
my @singlelines = split('',$currquest);
foreach my $entry (@singlelines) {
$occurrences = &occurence_count($entry,$matchon);
if ($occurrences > 1) {
last;
}
- }
+ }
} else {
$occurrences = &occurence_count($currquest,$matchon);
}
@@ -6027,7 +6221,8 @@ sub scantron_validator_lettnum {
sub scantron_validator_positional {
my ($ansnum,$questnum,$quest_id,$answers_needed,$currquest,
- $whichline,$alphabet,$record,$scantron_config,$scan_data) = @_;
+ $whichline,$alphabet,$record,$scantron_config,$scan_data,
+ $randomorder,$randompick,$respnumlookup) = @_;
# Otherwise there's a positional notation;
# each bubble line requires Qlength items, and there are filled in
@@ -6069,12 +6264,16 @@ sub scantron_validator_positional {
# record all the bubbles filled in as well as the
# fact this response consists of multiple bubbles.
#
- if (($responsetype_per_response{$questnum-1} eq 'essayresponse') ||
- ($responsetype_per_response{$questnum-1} eq 'formularesponse') ||
- ($responsetype_per_response{$questnum-1} eq 'stringresponse') ||
- ($responsetype_per_response{$questnum-1} eq 'imageresponse') ||
- ($responsetype_per_response{$questnum-1} eq 'reactionresponse') ||
- ($responsetype_per_response{$questnum-1} eq 'organicresponse')) {
+ my $responsenum = $questnum-1;
+ if (($randompick || $randomorder) && (ref($respnumlookup) eq 'HASH')) {
+ $responsenum = $respnumlookup->{$questnum-1}
+ }
+ if (($responsetype_per_response{$responsenum} eq 'essayresponse') ||
+ ($responsetype_per_response{$responsenum} eq 'formularesponse') ||
+ ($responsetype_per_response{$responsenum} eq 'stringresponse') ||
+ ($responsetype_per_response{$responsenum} eq 'imageresponse') ||
+ ($responsetype_per_response{$responsenum} eq 'reactionresponse') ||
+ ($responsetype_per_response{$responsenum} eq 'organicresponse')) {
my $doubleerror = 0;
while (($currquest >= $$scantron_config{'Qlength'}) &&
(!$doubleerror)) {
@@ -6256,7 +6455,11 @@ sub scantron_process_corrections {
}
}
if ($err) {
- $r->print("Unable to accept last correction, an error occurred :$errmsg: ");
+ $r->print(
+ ''
+ .&mt('Unable to accept last correction, an error occurred: [_1]',
+ $errmsg)
+ .'
');
} else {
&scantron_put_line($scanlines,$scan_data,$which,$line,$skip);
&scantron_putfile($scanlines,$scan_data);
@@ -6370,7 +6573,7 @@ sub check_for_error {
=cut
sub scantron_warning_screen {
- my ($button_text)=@_;
+ my ($button_text,$symb)=@_;
my $title=&Apache::lonnet::gettitle($env{'form.selectpage'});
my %scantron_config=&get_scantron_config($env{'form.scantron_format'});
my $CODElist;
@@ -6383,19 +6586,24 @@ sub scantron_warning_screen {
' '.&mt('List of CODES to validate against:').' '.
$env{'form.scantron_CODElist'}.' ';
}
+ my $lastbubblepoints;
+ if ($env{'form.scantron_lastbubblepoints'} ne '') {
+ $lastbubblepoints =
+ ''.&mt('Hand-graded items: points from last bubble in row').' '.
+ $env{'form.scantron_lastbubblepoints'}.' ';
+ }
return ('
-'.&mt('Please double check the information below before clicking on \'[_1]\'',&mt($button_text)).'
+'.&mt("Please double check the information below before clicking on '[_1]'",&mt($button_text)).'
'.&mt('Sequence to be Graded:').' '.$title.'
'.&mt('Data File that will be used:').' '.$env{'form.scantron_selectfile'}.'
-'.$CODElist.'
+'.$CODElist.$lastbubblepoints.'
-
- '.&mt('If this information is correct, please click on \'[_1]\'.',&mt($button_text)).'
- '.&mt('If something is incorrect, please click the \'Grading Menu\' button to start over.').'
+ '.&mt("If this information is correct, please click on '[_1]'.",&mt($button_text)).'
+'.&mt('If something is incorrect, please return to [_1]Grade/Manage/Review Bubblesheets[_2] to start over.','',' ').'
');
@@ -6411,8 +6619,7 @@ sub scantron_warning_screen {
=cut
sub scantron_do_warning {
- my ($r)=@_;
- my ($symb)=&get_symb($r);
+ my ($r,$symb)=@_;
if (!$symb) {return '';}
my $default_form_data=&defaultFormData($symb);
$r->print(&scantron_form_start().$default_form_data);
@@ -6430,14 +6637,15 @@ sub scantron_do_warning {
$r->print(''.&mt("You have not selected the format of the student's response data.").'
');
}
} else {
- my $warning=&scantron_warning_screen('Grading: Validate Records');
+ my $warning=&scantron_warning_screen('Grading: Validate Records',$symb);
+ my $bubbledbyhand=&hand_bubble_option();
$r->print('
-'.$warning.'
+'.$warning.$bubbledbyhand.'
');
}
- $r->print(" ".&show_grading_menu_form($symb));
+ $r->print(" ");
return '';
}
@@ -6474,9 +6682,11 @@ SCANTRONFORM
' '."\n";
$chunk .=
' '."\n";
+ $chunk .=
+ ' '."\n";
$result .= $chunk;
$line++;
- }
+ }
return $result;
}
@@ -6493,12 +6703,11 @@ SCANTRONFORM
=cut
sub scantron_validate_file {
- my ($r) = @_;
- my ($symb)=&get_symb($r);
+ my ($r,$symb) = @_;
if (!$symb) {return '';}
my $default_form_data=&defaultFormData($symb);
- # do the detection of only doing skipped records first befroe we delete
+ # do the detection of only doing skipped records first before we delete
# them when doing the corrections reset
if ($env{'form.scantron_options_redo'} ne 'redo_skipped_ready') {
&reset_skipping_status();
@@ -6529,6 +6738,9 @@ sub scantron_validate_file {
return '';
}
my $result=&scantron_form_start($max_bubble).$default_form_data;
+ if ($env{'form.scantron_lastbubblepoints'} ne '') {
+ $result .= ' ';
+ }
$r->print($result);
my @validate_phases=( 'sequence',
@@ -6546,6 +6758,7 @@ sub scantron_validate_file {
while (!$stop && $currentphase < scalar(@validate_phases)) {
$r->print(&mt('Validating '.$validate_phases[$currentphase]).' ');
$r->rflush();
+
my $which="scantron_validate_".$validate_phases[$currentphase];
{
no strict 'refs';
@@ -6553,7 +6766,7 @@ sub scantron_validate_file {
}
}
if (!$stop) {
- my $warning=&scantron_warning_screen('Start Grading');
+ my $warning=&scantron_warning_screen('Start Grading',$symb);
$r->print(&mt('Validation process complete.').' '.
$warning.
&mt('Perform verification for each student after storage of submissions?').
@@ -6563,7 +6776,7 @@ sub scantron_validate_file {
' '.&mt('No').
' '.
&mt('Grading will take longer if you use verification.').' '.
- &mt("Alternatively, the 'Review bubblesheet data' utility (see grading menu) can be used for all students after grading is complete.").' '.
+ &mt('Otherwise, Grade/Manage/Review Bubblesheets [_1] Review bubblesheet data can be used once grading is complete.','»').' '.
' '.
' '."\n");
} else {
@@ -6575,7 +6788,7 @@ sub scantron_validate_file {
$r->print(' ');
$r->print(' '.&mt('this error').' ');
- $r->print(" ".&mt("Or click the 'Grading Menu' button to start over.")."
");
+ $r->print(''.&mt('Or return to [_1]Grade/Manage/Review Bubblesheets[_2] to start over.','',' ').'
');
} else {
if ($validate_phases[$currentphase] eq 'doublebubble' || $validate_phases[$currentphase] eq 'missingbubbles') {
$r->print(' ');
@@ -6587,7 +6800,7 @@ sub scantron_validate_file {
$r->print(" ".&mt("this scanline saving it for later."));
}
}
- $r->print(" ".&show_grading_menu_form($symb));
+ $r->print(" ");
return '';
}
@@ -6954,7 +7167,13 @@ sub scantron_validate_sequence {
my @resources=
$navmap->retrieveResources($map,\&scantron_filter_not_exam,1,0);
if (@resources) {
- $r->print("".&mt('Some resources in the sequence currently are not set to exam mode. Grading these resources currently may not work correctly.')."
");
+ $r->print(
+ ''
+ .&mt('Some resources in the sequence currently are not set to'
+ .' bubblesheet exam mode. Grading these resources currently may not'
+ .' work correctly.')
+ .'
'
+ );
return (1,$currentphase);
}
}
@@ -7035,7 +7254,8 @@ sub scantron_validate_ID {
sub scantron_get_correction {
- my ($r,$i,$scan_record,$scan_config,$line,$error,$arg)=@_;
+ my ($r,$i,$scan_record,$scan_config,$line,$error,$arg,
+ $randomorder,$randompick,$respnumlookup,$startline)=@_;
#FIXME in the case of a duplicated ID the previous line, probably need
#to show both the current line and the previous one and allow skipping
#the previous one or the current one
@@ -7072,10 +7292,10 @@ sub scantron_get_correction {
if ($error =~ /ID$/) {
if ($error eq 'incorrectID') {
- $r->print(''.&mt("The encoded ID is not in the classlist").
+ $r->print('
'.&mt("The encoded ID is not in the classlist").
"
\n");
} elsif ($error eq 'duplicateID') {
- $r->print(''.&mt("The encoded ID has also been used by a previous paper [_1]",$arg)."
\n");
+ $r->print(''.&mt("The encoded ID has also been used by a previous paper [_1]",$arg)."
\n");
}
$r->print($message);
$r->print("".&mt("How should I handle this?")." \n");
@@ -7085,7 +7305,7 @@ sub scantron_get_correction {
$r->print(&Apache::loncommon::selectstudent_link('scantronupload',
'scantron_username','scantron_domain'));
$r->print(": ");
- $r->print("\n@".
+ $r->print("\n:\n".
&Apache::loncommon::select_dom_form($env{'request.role.domain'},'scantron_domain'));
$r->print('');
@@ -7095,8 +7315,8 @@ sub scantron_get_correction {
} elsif ($error eq 'duplicateCODE') {
$r->print('
'.&mt("The encoded CODE has also been used by a previous paper [_1], and CODEs are supposed to be unique.",join(', ',@{$arg}))."
\n");
}
- $r->print("".&mt('The CODE on the form is [_1]',
- "'$$scan_record{'scantron.CODE'}' ")
+ $r->print("
".&mt('The CODE on the form is [_1]',
+ "'$$scan_record{'scantron.CODE'}' ")
."
\n");
$r->print($message);
$r->print("".&mt("How should I handle this?")."
\n");
@@ -7132,8 +7352,7 @@ sub scantron_get_correction {
$r->print("\n ");
}
- $r->print(<
+ $r->print(&Apache::lonhtmlcommon::scripttag(<
ENDSCRIPT
my $href="/adm/pickcode?".
"form=".&escape("scantronupload").
@@ -7171,7 +7389,8 @@ ENDSCRIPT
# The form field scantron_questions is acutally a list of line numbers.
# represented by this form so:
- my $line_list = &questions_to_line_list($arg);
+ my $line_list = &questions_to_line_list($arg,$randomorder,$randompick,
+ $respnumlookup,$startline);
$r->print(' ');
@@ -7179,7 +7398,9 @@ ENDSCRIPT
$r->print("".&mt("Please indicate which bubble should be used for grading")."
");
foreach my $question (@{$arg}) {
my @linenums = &prompt_for_corrections($r,$question,$scan_config,
- $scan_record, $error);
+ $scan_record, $error,
+ $randomorder,$randompick,
+ $respnumlookup,$startline);
push(@lines_to_correct,@linenums);
}
$r->print(&verify_bubbles_checked(@lines_to_correct));
@@ -7192,14 +7413,17 @@ ENDSCRIPT
# The form field scantron_questions is actually a list of line numbers not
# a list of question numbers. Therefore:
#
-
- my $line_list = &questions_to_line_list($arg);
+
+ my $line_list = &questions_to_line_list($arg,$randomorder,$randompick,
+ $respnumlookup,$startline);
$r->print(' ');
foreach my $question (@{$arg}) {
my @linenums = &prompt_for_corrections($r,$question,$scan_config,
- $scan_record, $error);
+ $scan_record, $error,
+ $randomorder,$randompick,
+ $respnumlookup,$startline);
push(@lines_to_correct,@linenums);
}
$r->print(&verify_bubbles_checked(@lines_to_correct));
@@ -7213,8 +7437,7 @@ sub verify_bubbles_checked {
my (@ansnums) = @_;
my $ansnumstr = join('","',@ansnums);
my $warning = &mt("A bubble or 'No bubble' selection has not been made for one or more lines.");
- my $output = (<
+ my $output = &Apache::lonhtmlcommon::scripttag((<
ENDSCRIPT
return $output;
}
@@ -7252,12 +7474,20 @@ used to fill in the scantron_questions f
Arguments:
questions - Reference to an array of questions.
+ randomorder - True if randomorder in use.
+ randompick - True if randompick in use.
+ respnumlookup - Reference to HASH mapping question numbers in bubble lines
+ for current line to question number used for same question
+ in "Master Seqence" (as seen by Course Coordinator).
+ startline - Reference to hash where key is question number (0 is first)
+ and key is number of first bubble line for current student
+ or code-based randompick and/or randomorder.
=cut
sub questions_to_line_list {
- my ($questions) = @_;
+ my ($questions,$randomorder,$randompick,$respnumlookup,$startline) = @_;
my @lines;
foreach my $item (@{$questions}) {
@@ -7266,8 +7496,16 @@ sub questions_to_line_list {
if ($item =~ /^(\d+)\.(\d+)$/) {
$question = $1;
my $subquestion = $2;
- $first = $first_bubble_line{$question-1} + 1;
- my @subans = split(/,/,$subdivided_bubble_lines{$question-1});
+ my $responsenum = $question-1;
+ if (($randomorder || $randompick) && (ref($respnumlookup) eq 'HASH')) {
+ $responsenum = $respnumlookup->{$question-1};
+ if (ref($startline) eq 'HASH') {
+ $first = $startline->{$question-1} + 1;
+ }
+ } else {
+ $first = $first_bubble_line{$responsenum} + 1;
+ }
+ my @subans = split(/,/,$subdivided_bubble_lines{$responsenum});
my $subcount = 1;
while ($subcount<$subquestion) {
$first += $subans[$subcount-1];
@@ -7275,8 +7513,16 @@ sub questions_to_line_list {
}
$count = $subans[$subquestion-1];
} else {
- $first = $first_bubble_line{$question-1} + 1;
- $count = $bubble_lines_per_response{$question-1};
+ my $responsenum = $question-1;
+ if (($randomorder || $randompick) && (ref($respnumlookup) eq 'HASH')) {
+ $responsenum = $respnumlookup->{$question-1};
+ if (ref($startline) eq 'HASH') {
+ $first = $startline->{$question-1} + 1;
+ }
+ } else {
+ $first = $first_bubble_line{$responsenum} + 1;
+ }
+ $count = $bubble_lines_per_response{$responsenum};
}
$last = $first+$count-1;
push(@lines, ($first..$last));
@@ -7298,6 +7544,15 @@ for multi and missing bubble cases).
$scan_config - The scantron file configuration hash.
$scan_record - Reference to the hash that has the the parsed scanlines.
$error - Type of error
+ $randomorder - True if randomorder in use.
+ $randompick - True if randompick in use.
+ $respnumlookup - Reference to HASH mapping question numbers in bubble lines
+ for current line to question number used for same question
+ in "Master Seqence" (as seen by Course Coordinator).
+ $startline - Reference to hash where key is question number (0 is first)
+ and value is number of first bubble line for current student
+ or code-based randompick and/or randomorder.
+
Implicit inputs:
%bubble_lines_per_response - Starting line numbers for each question.
@@ -7322,15 +7577,26 @@ for multi and missing bubble cases).
=cut
sub prompt_for_corrections {
- my ($r, $question, $scan_config, $scan_record, $error) = @_;
+ my ($r, $question, $scan_config, $scan_record, $error, $randomorder,
+ $randompick, $respnumlookup, $startline) = @_;
my ($current_line,$lines);
my @linenums;
my $questionnum = $question;
+ my ($first,$responsenum);
if ($question =~ /^(\d+)\.(\d+)$/) {
$question = $1;
- $current_line = $first_bubble_line{$question-1} + 1 ;
my $subquestion = $2;
- my @subans = split(/,/,$subdivided_bubble_lines{$question-1});
+ if (($randomorder || $randompick) && (ref($respnumlookup) eq 'HASH')) {
+ $responsenum = $respnumlookup->{$question-1};
+ if (ref($startline) eq 'HASH') {
+ $first = $startline->{$question-1};
+ }
+ } else {
+ $responsenum = $question-1;
+ $first = $first_bubble_line{$responsenum};
+ }
+ $current_line = $first + 1 ;
+ my @subans = split(/,/,$subdivided_bubble_lines{$responsenum});
my $subcount = 1;
while ($subcount<$subquestion) {
$current_line += $subans[$subcount-1];
@@ -7338,25 +7604,43 @@ sub prompt_for_corrections {
}
$lines = $subans[$subquestion-1];
} else {
- $current_line = $first_bubble_line{$question-1} + 1 ;
- $lines = $bubble_lines_per_response{$question-1};
+ if (($randomorder || $randompick) && (ref($respnumlookup) eq 'HASH')) {
+ $responsenum = $respnumlookup->{$question-1};
+ if (ref($startline) eq 'HASH') {
+ $first = $startline->{$question-1};
+ }
+ } else {
+ $responsenum = $question-1;
+ $first = $first_bubble_line{$responsenum};
+ }
+ $current_line = $first + 1;
+ $lines = $bubble_lines_per_response{$responsenum};
}
if ($lines > 1) {
$r->print(&mt('The group of bubble lines below responds to a single question.').' ');
- if (($responsetype_per_response{$question-1} eq 'essayresponse') ||
- ($responsetype_per_response{$question-1} eq 'formularesponse') ||
- ($responsetype_per_response{$question-1} eq 'stringresponse') ||
- ($responsetype_per_response{$question-1} eq 'imageresponse') ||
- ($responsetype_per_response{$question-1} eq 'reactionresponse') ||
- ($responsetype_per_response{$question-1} eq 'organicresponse')) {
- $r->print(&mt("Although this particular question type requires handgrading, the instructions for this question in the exam directed students to leave [quant,_1,line] blank on their bubblesheets.",$lines).' '.&mt('A non-zero score can be assigned to the student during bubblesheet grading by selecting a bubble in at least one line.').' '.&mt('The score for this question will be a sum of the numeric values for the selected bubbles from each line, where A=1 point, B=2 points etc.').' '.&mt("To assign a score of zero for this question, mark all lines as 'No bubble'.").' ');
+ if (($responsetype_per_response{$responsenum} eq 'essayresponse') ||
+ ($responsetype_per_response{$responsenum} eq 'formularesponse') ||
+ ($responsetype_per_response{$responsenum} eq 'stringresponse') ||
+ ($responsetype_per_response{$responsenum} eq 'imageresponse') ||
+ ($responsetype_per_response{$responsenum} eq 'reactionresponse') ||
+ ($responsetype_per_response{$responsenum} eq 'organicresponse')) {
+ $r->print(
+ &mt("Although this particular question type requires handgrading, the instructions for this question in the bubblesheet exam directed students to leave [quant,_1,line] blank on their bubblesheets.",$lines)
+ .' '
+ .&mt('A non-zero score can be assigned to the student during bubblesheet grading by selecting a bubble in at least one line.')
+ .' '
+ .&mt('The score for this question will be a sum of the numeric values for the selected bubbles from each line, where A=1 point, B=2 points etc.')
+ .' '
+ .&mt("To assign a score of zero for this question, mark all lines as 'No bubble'.")
+ .' '
+ );
} else {
$r->print(&mt("Select at most one bubble in a single line and select 'No Bubble' in all the other lines. ")." ");
}
}
for (my $i =0; $i < $lines; $i++) {
my $selected = $$scan_record{"scantron.$current_line.answer"};
- &scantron_bubble_selector($r,$scan_config,$current_line,
+ &scantron_bubble_selector($r,$scan_config,$current_line,
$questionnum,$error,split('', $selected));
push(@linenums,$current_line);
$current_line++;
@@ -7389,7 +7673,7 @@ sub scantron_bubble_selector {
my $max=$$scan_config{'Qlength'};
my $scmode=$$scan_config{'Qon'};
- if ($scmode eq 'number' || $scmode eq 'letter') {
+ if ($scmode eq 'number' || $scmode eq 'letter') {
if (($$scan_config{'BubblesPerRow'} =~ /^\d+$/) &&
($$scan_config{'BubblesPerRow'} > 0)) {
$max=$$scan_config{'BubblesPerRow'};
@@ -7610,11 +7894,42 @@ sub scantron_validate_doublebubble {
#get student info
my $classlist=&Apache::loncoursedata::get_classlist();
my %idmap=&username_to_idmap($classlist);
+ my (undef,undef,$sequence)=
+ &Apache::lonnet::decode_symb($env{'form.selectpage'});
#get scantron line setup
my %scantron_config=&get_scantron_config($env{'form.scantron_format'});
my ($scanlines,$scan_data)=&scantron_getfile();
+
+ my $navmap = Apache::lonnavmaps::navmap->new();
+ unless (ref($navmap)) {
+ $r->print(&navmap_errormsg());
+ return(1,$currentphase);
+ }
+ my $map=$navmap->getResourceByUrl($sequence);
+ my @resources=$navmap->retrieveResources($map,\&scantron_filter,1,0);
+ my ($randomorder,$randompick,@master_seq,%symb_to_resource,%grader_partids_by_symb,
+ %grader_randomlists_by_symb,%orderedforcode,%respnumlookup,%startline);
+ my $bubbles_per_row = &bubblesheet_bubbles_per_row(\%scantron_config);
+
my $nav_error;
+ if (ref($map)) {
+ $randomorder = $map->randomorder();
+ $randompick = $map->randompick();
+ if ($randomorder || $randompick) {
+ $nav_error = &get_master_seq(\@resources,\@master_seq,\%symb_to_resource);
+ if ($nav_error) {
+ $r->print(&navmap_errormsg());
+ return(1,$currentphase);
+ }
+ &graders_resources_pass(\@resources,\%grader_partids_by_symb,
+ \%grader_randomlists_by_symb,$bubbles_per_row);
+ }
+ } else {
+ $r->print(&navmap_errormsg());
+ return(1,$currentphase);
+ }
+
&scantron_get_maxbubble(\$nav_error,\%scantron_config); # parse needs the bubble line array.
if ($nav_error) {
$r->print(&navmap_errormsg());
@@ -7625,11 +7940,15 @@ sub scantron_validate_doublebubble {
my $line=&scantron_get_line($scanlines,$scan_data,$i);
if ($line=~/^[\s\cz]*$/) { next; }
my $scan_record=&scantron_parse_scanline($line,$i,\%scantron_config,
- $scan_data);
+ $scan_data,undef,\%idmap,$randomorder,
+ $randompick,$sequence,\@master_seq,
+ \%symb_to_resource,\%grader_partids_by_symb,
+ \%orderedforcode,\%respnumlookup,\%startline);
if (!defined($$scan_record{'scantron.doubleerror'})) { next; }
&scantron_get_correction($r,$i,$scan_record,\%scantron_config,$line,
'doublebubble',
- $$scan_record{'scantron.doubleerror'});
+ $$scan_record{'scantron.doubleerror'},
+ $randomorder,$randompick,\%respnumlookup,\%startline);
return (1,$currentphase);
}
return (0,$currentphase+1);
@@ -7668,12 +7987,14 @@ sub scantron_get_maxbubble {
%first_bubble_line = ();
%subdivided_bubble_lines = ();
%responsetype_per_response = ();
+ %masterseq_id_responsenum = ();
my $response_number = 0;
my $bubble_line = 0;
foreach my $resource (@resources) {
+ my $resid = $resource->id();
my ($analysis,$parts) = &scantron_partids_tograde($resource,$cid,$uname,
- $udom,$bubbles_per_row);
+ $udom,undef,$bubbles_per_row);
if ((ref($analysis) eq 'HASH') && (ref($parts) eq 'ARRAY')) {
foreach my $part_id (@{$parts}) {
my $lines;
@@ -7722,6 +8043,7 @@ sub scantron_get_maxbubble {
$bubble_lines_per_response{$response_number} = $lines;
$responsetype_per_response{$response_number} =
$analysis->{$part_id.'.type'};
+ $masterseq_id_responsenum{$resid.'_'.$part_id} = $response_number;
$response_number++;
$bubble_line += $lines;
@@ -7754,21 +8076,59 @@ sub scantron_validate_missingbubbles {
#get student info
my $classlist=&Apache::loncoursedata::get_classlist();
my %idmap=&username_to_idmap($classlist);
+ my (undef,undef,$sequence)=
+ &Apache::lonnet::decode_symb($env{'form.selectpage'});
#get scantron line setup
my %scantron_config=&get_scantron_config($env{'form.scantron_format'});
my ($scanlines,$scan_data)=&scantron_getfile();
+
+ my $navmap = Apache::lonnavmaps::navmap->new();
+ unless (ref($navmap)) {
+ $r->print(&navmap_errormsg());
+ return(1,$currentphase);
+ }
+
+ my $map=$navmap->getResourceByUrl($sequence);
+ my @resources=$navmap->retrieveResources($map,\&scantron_filter,1,0);
+ my ($randomorder,$randompick,@master_seq,%symb_to_resource,%grader_partids_by_symb,
+ %grader_randomlists_by_symb,%orderedforcode,%respnumlookup,%startline);
+ my $bubbles_per_row = &bubblesheet_bubbles_per_row(\%scantron_config);
+
my $nav_error;
+ if (ref($map)) {
+ $randomorder = $map->randomorder();
+ $randompick = $map->randompick();
+ if ($randomorder || $randompick) {
+ $nav_error = &get_master_seq(\@resources,\@master_seq,\%symb_to_resource);
+ if ($nav_error) {
+ $r->print(&navmap_errormsg());
+ return(1,$currentphase);
+ }
+ &graders_resources_pass(\@resources,\%grader_partids_by_symb,
+ \%grader_randomlists_by_symb,$bubbles_per_row);
+ }
+ } else {
+ $r->print(&navmap_errormsg());
+ return(1,$currentphase);
+ }
+
+
my $max_bubble=&scantron_get_maxbubble(\$nav_error,\%scantron_config);
if ($nav_error) {
+ $r->print(&navmap_errormsg());
return(1,$currentphase);
}
+
if (!$max_bubble) { $max_bubble=2**31; }
for (my $i=0;$i<=$scanlines->{'count'};$i++) {
my $line=&scantron_get_line($scanlines,$scan_data,$i);
if ($line=~/^[\s\cz]*$/) { next; }
- my $scan_record=&scantron_parse_scanline($line,$i,\%scantron_config,
- $scan_data);
+ my $scan_record =
+ &scantron_parse_scanline($line,$i,\%scantron_config,$scan_data,undef,\%idmap,
+ $randomorder,$randompick,$sequence,\@master_seq,
+ \%symb_to_resource,\%grader_partids_by_symb,
+ \%orderedforcode,\%respnumlookup,\%startline);
if (!defined($$scan_record{'scantron.missingerror'})) { next; }
my @to_correct;
@@ -7779,9 +8139,16 @@ sub scantron_validate_missingbubbles {
if ($missing =~ /^(\d+)\.(\d+)$/) {
my $question = $1;
my $subquestion = $2;
- if (!defined($first_bubble_line{$question -1})) { next; }
- my $first = $first_bubble_line{$question-1};
- my @subans = split(/,/,$subdivided_bubble_lines{$question-1});
+ my ($first,$responsenum);
+ if ($randomorder || $randompick) {
+ $responsenum = $respnumlookup{$question-1};
+ $first = $startline{$question-1};
+ } else {
+ $responsenum = $question-1;
+ $first = $first_bubble_line{$responsenum};
+ }
+ if (!defined($first)) { next; }
+ my @subans = split(/,/,$subdivided_bubble_lines{$responsenum});
my $subcount = 1;
while ($subcount<$subquestion) {
$first += $subans[$subcount-1];
@@ -7790,15 +8157,25 @@ sub scantron_validate_missingbubbles {
my $count = $subans[$subquestion-1];
$lastbubble = $first + $count;
} else {
- if (!defined($first_bubble_line{$missing - 1})) { next; }
- $lastbubble = $first_bubble_line{$missing - 1} + $bubble_lines_per_response{$missing - 1};
+ my ($first,$responsenum);
+ if ($randomorder || $randompick) {
+ $responsenum = $respnumlookup{$missing-1};
+ $first = $startline{$missing-1};
+ } else {
+ $responsenum = $missing-1;
+ $first = $first_bubble_line{$responsenum};
+ }
+ if (!defined($first)) { next; }
+ $lastbubble = $first + $bubble_lines_per_response{$responsenum};
}
if ($lastbubble > $max_bubble) { next; }
push(@to_correct,$missing);
}
if (@to_correct) {
&scantron_get_correction($r,$i,$scan_record,\%scantron_config,
- $line,'missingbubble',\@to_correct);
+ $line,'missingbubble',\@to_correct,
+ $randomorder,$randompick,\%respnumlookup,
+ \%startline);
return (1,$currentphase);
}
@@ -7806,18 +8183,53 @@ sub scantron_validate_missingbubbles {
return (0,$currentphase+1);
}
+sub hand_bubble_option {
+ my (undef, undef, $sequence) =
+ &Apache::lonnet::decode_symb($env{'form.selectpage'});
+ return if ($sequence eq '');
+ my $navmap = Apache::lonnavmaps::navmap->new();
+ unless (ref($navmap)) {
+ return;
+ }
+ my $needs_hand_bubbles;
+ my $map=$navmap->getResourceByUrl($sequence);
+ my @resources=$navmap->retrieveResources($map,\&scantron_filter,1,0);
+ foreach my $res (@resources) {
+ if (ref($res)) {
+ if ($res->is_problem()) {
+ my $partlist = $res->parts();
+ foreach my $part (@{ $partlist }) {
+ my @types = $res->responseType($part);
+ if (grep(/^(chem|essay|image|formula|math|string|functionplot)$/,@types)) {
+ $needs_hand_bubbles = 1;
+ last;
+ }
+ }
+ }
+ }
+ }
+ if ($needs_hand_bubbles) {
+ my %scantron_config=&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.').''.
+ &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?',' ').
+ ' '.&mt('[quant,_1,point]',$bubbles_per_row).' '.&mt('or').' '.
+ ' 0 points
';
+ }
+ return;
+}
sub scantron_process_students {
- my ($r) = @_;
+ my ($r,$symb) = @_;
my (undef,undef,$sequence)=&Apache::lonnet::decode_symb($env{'form.selectpage'});
- my ($symb)=&get_symb($r);
if (!$symb) {
return '';
}
my $default_form_data=&defaultFormData($symb);
my %scantron_config=&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();
my %idmap=&username_to_idmap($classlist);
@@ -7825,37 +8237,28 @@ sub scantron_process_students {
unless (ref($navmap)) {
$r->print(&navmap_errormsg());
return '';
- }
- my $map=$navmap->getResourceByUrl($sequence);
- my @resources=$navmap->retrieveResources($map,\&scantron_filter,1,0);
- my (%grader_partids_by_symb,%grader_randomlists_by_symb);
- &graders_resources_pass(\@resources,\%grader_partids_by_symb,
- \%grader_randomlists_by_symb);
- my $resource_error;
- foreach my $resource (@resources) {
- my $ressymb;
- if (ref($resource)) {
- $ressymb = $resource->symb();
- } else {
- $resource_error = 1;
- last;
- }
- my ($analysis,$parts) =
- &scantron_partids_tograde($resource,$env{'request.course.id'},
- $env{'user.name'},$env{'user.domain'},
- 1,$bubbles_per_row);
- $grader_partids_by_symb{$ressymb} = $parts;
- if (ref($analysis) eq 'HASH') {
- if (ref($analysis->{'parts_withrandomlist'}) eq 'ARRAY') {
- $grader_randomlists_by_symb{$ressymb} =
- $analysis->{'parts_withrandomlist'};
- }
- }
}
- if ($resource_error) {
+ my $map=$navmap->getResourceByUrl($sequence);
+ my ($randomorder,$randompick,@master_seq,%symb_to_resource,%grader_partids_by_symb,
+ %grader_randomlists_by_symb);
+ if (ref($map)) {
+ $randomorder = $map->randomorder();
+ $randompick = $map->randompick();
+ } else {
$r->print(&navmap_errormsg());
return '';
}
+ my $nav_error;
+ my @resources=$navmap->retrieveResources($map,\&scantron_filter,1,0);
+ if ($randomorder || $randompick) {
+ $nav_error = &get_master_seq(\@resources,\@master_seq,\%symb_to_resource);
+ if ($nav_error) {
+ $r->print(&navmap_errormsg());
+ return '';
+ }
+ }
+ &graders_resources_pass(\@resources,\%grader_partids_by_symb,
+ \%grader_randomlists_by_symb,$bubbles_per_row);
my ($uname,$udom);
my $result= <print(' ');
my $start=&Time::HiRes::time();
my $i=-1;
my $started;
- my $nav_error;
&scantron_get_maxbubble(\$nav_error,\%scantron_config); # Need the bubble lines array to parse.
if ($nav_error) {
$r->print(&navmap_errormsg());
@@ -7893,13 +8292,13 @@ SCANTRONFORM
if ($ssi_error) {
$r->print("");
&ssi_print_error($r);
- $r->print(&show_grading_menu_form($symb));
&Apache::lonnet::remove_lock($lock);
return ''; # Dunno why the other returns return '' rather than just returning.
}
my %lettdig = &letter_to_digits();
my $numletts = scalar(keys(%lettdig));
+ my %orderedforcode;
while ($i<$scanlines->{'count'}) {
($uname,$udom)=('','');
@@ -7907,12 +8306,18 @@ SCANTRONFORM
my $line=&scantron_get_line($scanlines,$scan_data,$i);
if ($line=~/^[\s\cz]*$/) { next; }
if ($started) {
- &Apache::lonhtmlcommon::Increment_PrgWin($r,\%prog_state,
- 'last student');
+ &Apache::lonhtmlcommon::Increment_PrgWin($r,\%prog_state,'last student');
}
$started=1;
+ my %respnumlookup = ();
+ my %startline = ();
+ my $total;
my $scan_record=&scantron_parse_scanline($line,$i,\%scantron_config,
- $scan_data);
+ $scan_data,undef,\%idmap,$randomorder,
+ $randompick,$sequence,\@master_seq,
+ \%symb_to_resource,\%grader_partids_by_symb,
+ \%orderedforcode,\%respnumlookup,\%startline,
+ \$total);
unless ($uname=&scantron_find_student($scan_record,$scan_data,
\%idmap,$i)) {
&scantron_add_delay(\@delayqueue,$line,
@@ -7924,10 +8329,26 @@ SCANTRONFORM
'Student '.$uname.' has multiple sheets',2);
next;
}
+ my $usec = $classlist->{$uname}->[&Apache::loncoursedata::CL_SECTION];
+ my $user = $uname.':'.$usec;
($uname,$udom)=split(/:/,$uname);
+ my $scancode;
+ if ((exists($scan_record->{'scantron.CODE'})) &&
+ (&Apache::lonnet::validCODE($scan_record->{'scantron.CODE'}))) {
+ $scancode = $scan_record->{'scantron.CODE'};
+ } else {
+ $scancode = '';
+ }
+
+ my @mapresources = @resources;
+ if ($randomorder || $randompick) {
+ @mapresources =
+ &users_order($user,$scancode,$sequence,\@master_seq,\%symb_to_resource,
+ \%orderedforcode);
+ }
my (%partids_by_symb,$res_error);
- foreach my $resource (@resources) {
+ foreach my $resource (@mapresources) {
my $ressymb;
if (ref($resource)) {
$ressymb = $resource->symb();
@@ -7959,62 +8380,72 @@ SCANTRONFORM
&scantron_putfile($scanlines,$scan_data);
}
- my $scancode;
- if ((exists($scan_record->{'scantron.CODE'})) &&
- (&Apache::lonnet::validCODE($scan_record->{'scantron.CODE'}))) {
- $scancode = $scan_record->{'scantron.CODE'};
- } else {
- $scancode = '';
- }
-
if (&grade_student_bubbles($r,$uname,$udom,$scan_record,$scancode,
- \@resources,\%partids_by_symb,
- $bubbles_per_row) eq 'ssi_error') {
+ \@mapresources,\%partids_by_symb,
+ $bubbles_per_row,$randomorder,$randompick,
+ \%respnumlookup,\%startline)
+ eq 'ssi_error') {
$ssi_error = 0; # So end of handler error message does not trigger.
$r->print("");
&ssi_print_error($r);
- $r->print(&show_grading_menu_form($symb));
&Apache::lonnet::remove_lock($lock);
return ''; # Why return ''? Beats me.
}
+ if (($scancode) && ($randomorder || $randompick)) {
+ my $parmresult =
+ &Apache::lonparmset::storeparm_by_symb($symb,
+ '0_examcode',2,$scancode,
+ 'string_examcode',$uname,
+ $udom);
+ }
$completedstudents{$uname}={'line'=>$line};
if ($env{'form.verifyrecord'}) {
my $lastpos = $env{'form.scantron_maxbubble'}*$scantron_config{'Qlength'};
+ if ($randompick) {
+ if ($total) {
+ $lastpos = $total*$scantron_config{'Qlength'};
+ }
+ }
+
my $studentdata = substr($line,$scantron_config{'Qstart'}-1,$lastpos);
chomp($studentdata);
$studentdata =~ s/\r$//;
my $studentrecord = '';
my $counter = -1;
- foreach my $resource (@resources) {
+ foreach my $resource (@mapresources) {
my $ressymb = $resource->symb();
($counter,my $recording) =
&verify_scantron_grading($resource,$udom,$uname,$env{'request.course.id'},
$counter,$studentdata,$partids_by_symb{$ressymb},
- \%scantron_config,\%lettdig,$numletts);
+ \%scantron_config,\%lettdig,$numletts,$randomorder,
+ $randompick,\%respnumlookup,\%startline);
$studentrecord .= $recording;
}
if ($studentrecord ne $studentdata) {
&Apache::lonxml::clear_problem_counter();
if (&grade_student_bubbles($r,$uname,$udom,$scan_record,$scancode,
- \@resources,\%partids_by_symb,
- $bubbles_per_row) eq 'ssi_error') {
+ \@mapresources,\%partids_by_symb,
+ $bubbles_per_row,$randomorder,$randompick,
+ \%respnumlookup,\%startline)
+ eq 'ssi_error') {
$ssi_error = 0; # So end of handler error message does not trigger.
$r->print("");
&ssi_print_error($r);
- $r->print(&show_grading_menu_form($symb));
&Apache::lonnet::remove_lock($lock);
delete($completedstudents{$uname});
return '';
}
$counter = -1;
$studentrecord = '';
- foreach my $resource (@resources) {
+ foreach my $resource (@mapresources) {
my $ressymb = $resource->symb();
($counter,my $recording) =
&verify_scantron_grading($resource,$udom,$uname,$env{'request.course.id'},
$counter,$studentdata,$partids_by_symb{$ressymb},
- \%scantron_config,\%lettdig,$numletts);
+ \%scantron_config,\%lettdig,$numletts,
+ $randomorder,$randompick,\%respnumlookup,
+ \%startline);
$studentrecord .= $recording;
}
if ($studentrecord ne $studentdata) {
@@ -8032,11 +8463,11 @@ SCANTRONFORM
&Apache::loncommon::end_data_table_header_row()."\n".
&Apache::loncommon::start_data_table_row().
''.&mt('Bubblesheet').' '.
- ''.$studentdata.' '.
+ ''.$studentdata.' '.
&Apache::loncommon::end_data_table_row().
&Apache::loncommon::start_data_table_row().
''.&mt('Stored submissions').' '.
- ''.$studentrecord.' '."\n".
+ ''.$studentrecord.' '."\n".
&Apache::loncommon::end_data_table_row().
&Apache::loncommon::end_data_table().'');
} else {
@@ -8058,12 +8489,12 @@ SCANTRONFORM
# $r->print("took $lasttime
");
$r->print("");
- $r->print(&show_grading_menu_form($symb));
return '';
}
sub graders_resources_pass {
- my ($resources,$grader_partids_by_symb,$grader_randomlists_by_symb) = @_;
+ my ($resources,$grader_partids_by_symb,$grader_randomlists_by_symb,
+ $bubbles_per_row) = @_;
if ((ref($resources) eq 'ARRAY') && (ref($grader_partids_by_symb)) &&
(ref($grader_randomlists_by_symb) eq 'HASH')) {
foreach my $resource (@{$resources}) {
@@ -8084,8 +8515,67 @@ sub graders_resources_pass {
return;
}
+=pod
+
+=item users_order
+
+ Returns array of resources in current map, ordered based on either CODE,
+ if this is a CODEd exam, or based on student's identity if this is a
+ "NAMEd" exam.
+
+ Should be used when randomorder and/or randompick applied when the
+ corresponding exam was printed, prior to students completing bubblesheets
+ for the version of the exam the student received.
+
+=cut
+
+sub users_order {
+ my ($user,$scancode,$mapurl,$master_seq,$symb_to_resource,$orderedforcode) = @_;
+ my @mapresources;
+ unless ((ref($master_seq) eq 'ARRAY') && (ref($symb_to_resource) eq 'HASH')) {
+ return @mapresources;
+ }
+ if ($scancode) {
+ if ((ref($orderedforcode) eq 'HASH') && (ref($orderedforcode->{$scancode}) eq 'ARRAY')) {
+ @mapresources = @{$orderedforcode->{$scancode}};
+ } else {
+ $env{'form.CODE'} = $scancode;
+ my $actual_seq =
+ &Apache::lonprintout::master_seq_to_person_seq($mapurl,
+ $master_seq,
+ $user,$scancode,1);
+ if (ref($actual_seq) eq 'ARRAY') {
+ @mapresources = map { $symb_to_resource->{$_}; } @{$actual_seq};
+ if (ref($orderedforcode) eq 'HASH') {
+ if (@mapresources > 0) {
+ $orderedforcode->{$scancode} = \@mapresources;
+ }
+ }
+ }
+ delete($env{'form.CODE'});
+ }
+ } else {
+ my $actual_seq =
+ &Apache::lonprintout::master_seq_to_person_seq($mapurl,
+ $master_seq,
+ $user,undef,1);
+ if (ref($actual_seq) eq 'ARRAY') {
+ @mapresources =
+ map { $symb_to_resource->{$_}; } @{$actual_seq};
+ }
+ }
+ return @mapresources;
+}
+
sub grade_student_bubbles {
- my ($r,$uname,$udom,$scan_record,$scancode,$resources,$parts,$bubbles_per_row) = @_;
+ my ($r,$uname,$udom,$scan_record,$scancode,$resources,$parts,$bubbles_per_row,
+ $randomorder,$randompick,$respnumlookup,$startline) = @_;
+ my $uselookup = 0;
+ if (($randomorder || $randompick) && (ref($respnumlookup) eq 'HASH') &&
+ (ref($startline) eq 'HASH')) {
+ $uselookup = 1;
+ }
+
if (ref($resources) eq 'ARRAY') {
my $count = 0;
foreach my $resource (@{$resources}) {
@@ -8101,11 +8591,18 @@ sub grade_student_bubbles {
if ($bubbles_per_row ne '') {
$form{'bubbles_per_row'} = $bubbles_per_row;
}
+ if ($env{'form.scantron_lastbubblepoints'} ne '') {
+ $form{'scantron_lastbubblepoints'} = $env{'form.scantron_lastbubblepoints'};
+ }
if (ref($parts) eq 'HASH') {
if (ref($parts->{$ressymb}) eq 'ARRAY') {
foreach my $part (@{$parts->{$ressymb}}) {
- $form{'scantron_questnum_start.'.$part} =
- 1+$env{'form.scantron.first_bubble_line.'.$count};
+ if ($uselookup) {
+ $form{'scantron_questnum_start.'.$part} = $startline->{$count} + 1;
+ } else {
+ $form{'scantron_questnum_start.'.$part} =
+ 1+$env{'form.scantron.first_bubble_line.'.$count};
+ }
$count++;
}
}
@@ -8119,7 +8616,7 @@ sub grade_student_bubbles {
}
sub scantron_upload_scantron_data {
- my ($r)=@_;
+ my ($r,$symb)=@_;
my $dom = $env{'request.role.domain'};
my $domdesc = &Apache::lonnet::domain($dom,'description');
$r->print(&Apache::loncommon::coursebrowser_javascript($dom));
@@ -8128,11 +8625,10 @@ sub scantron_upload_scantron_data {
'coursename',$dom);
my $syllabuslink = ''.&mt('Syllabus').' '.
(' 'x2).&mt('(shows course personnel)');
- my $default_form_data=&defaultFormData(&get_symb($r,1));
+ my $default_form_data=&defaultFormData($symb);
my $nofile_alert = &mt('Please use the browse button to select a file from your local directory.');
my $nocourseid_alert = &mt("Please use the 'Select Course' link to open a separate window where you can search for a course to which a file can be uploaded.");
- $r->print('
-
-
+'));
+ $r->print('
'.&mt('Send bubblesheet data to a course').'
@@ -8189,8 +8685,7 @@ sub scantron_upload_scantron_data {
sub scantron_upload_scantron_data_save {
- my($r)=@_;
- my ($symb)=&get_symb($r,1);
+ my($r,$symb)=@_;
my $doanotherupload=
' '."\n".
' '."\n".
@@ -8200,37 +8695,42 @@ sub scantron_upload_scantron_data_save {
!&Apache::lonnet::allowed('usc',
$env{'form.domainid'}.'_'.$env{'form.courseid'})) {
$r->print(&mt("You are not allowed to upload bubblesheet data to the requested course.")." ");
- if ($symb) {
- $r->print(&show_grading_menu_form($symb));
- } else {
+ unless ($symb) {
$r->print($doanotherupload);
}
return '';
}
my %coursedata=&Apache::lonnet::coursedescription($env{'form.domainid'}.'_'.$env{'form.courseid'});
my $uploadedfile;
- $r->print(''.&mt("Uploading file to [_1]",$coursedata{'description'}).' ');
+ $r->print(''.&mt('Uploading file to [_1]','"'.$coursedata{'description'}.'"').'
');
if (length($env{'form.upfile'}) < 2) {
- $r->print(&mt('[_1]Error:[_2] The file you attempted to upload, [_3] contained no information. Please check that you entered the correct filename.','',' ',''.&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"').' '));
+ $r->print(
+ &Apache::lonhtmlcommon::confirm_success(
+ &mt('The file: [_1] you attempted to upload contained no information. Please check that you entered the correct filename.',
+ ''.&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"').' '),1));
} else {
my $result =
&Apache::lonnet::userfileupload('upfile','','scantron','','','',
$env{'form.courseid'},$env{'form.domainid'});
- if ($result =~ m{^/uploaded/}) {
- $r->print(&mt('[_1]Success:[_2] Successfully uploaded [_3] bytes of data into location: [_4]',
- '',' ',(length($env{'form.upfile'})-1),
- ''.$result.' '));
+ if ($result =~ m{^/uploaded/}) {
+ $r->print(
+ &Apache::lonhtmlcommon::confirm_success(&mt('Upload successful')).' '.
+ &mt('Uploaded [_1] bytes of data into location: [_2]',
+ (length($env{'form.upfile'})-1),
+ ''.$result.' '));
($uploadedfile) = ($result =~ m{/([^/]+)$});
$r->print(&validate_uploaded_scantron_file($env{'form.domainid'},
$env{'form.courseid'},$uploadedfile));
- } else {
- $r->print(&mt('[_1]Error:[_2] An error ([_3]) occurred when attempting to upload the file, [_4]',
- '',' ',$result,
+ } else {
+ $r->print(
+ &Apache::lonhtmlcommon::confirm_success(&mt('Upload failed'),1).' '.
+ &mt('An error ([_1]) occurred when attempting to upload the file: [_2]',
+ $result,
''.&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"').' '));
}
}
if ($symb) {
- $r->print(&scantron_selectphase($r,$uploadedfile));
+ $r->print(&scantron_selectphase($r,$uploadedfile,$symb));
} else {
$r->print($doanotherupload);
}
@@ -8247,7 +8747,7 @@ sub validate_uploaded_scantron_file {
my $output;
if (@lines) {
my (%counts,$max_match_format);
- my ($max_match_count,$max_match_pct) = (0,0);
+ my ($found_match_count,$max_match_count,$max_match_pct) = (0,0,0);
my $classlist = &Apache::loncoursedata::get_classlist($cdom,$cname);
my %idmap = &username_to_idmap($classlist);
foreach my $key (keys(%idmap)) {
@@ -8290,6 +8790,7 @@ sub validate_uploaded_scantron_file {
if (($max_match_format eq '') || ($percent_match > $max_match_pct)) {
$max_match_pct = $percent_match;
$max_match_format = $key;
+ $found_match_count = $counts{$key}{'found'};
$max_match_count = $counts{$key}{'total'};
}
}
@@ -8308,17 +8809,40 @@ sub validate_uploaded_scantron_file {
}
}
my $showpct = sprintf("%.0f",$max_match_pct).'%';
- $output .= ' '.&mt('Comparison of student IDs in the uploaded file with the course roster found matches for [_1] of the [_2] entries in the file (for the format defined for [_3]).',''.$showpct.' ',''.$max_match_count.' ',$format_descs).
- ' '.&mt('A low percentage of matches results from one of the following:').''.
- ''.&mt('The file was uploaded to the wrong course').' '.
- ''.&mt('The data are not in the format expected for the domain: [_1]',
- ''.$cdom.' ').' '.
- ''.&mt('Students did not bubble their IDs, or mis-bubbled them').' '.
- ''.&mt('The course roster is not up to date').' '.
- ' ';
+ $output .= ' ';
+ if ($found_match_count == $max_match_count) {
+ # 100% matching entries
+ $output .= &Apache::lonhtmlcommon::confirm_success(
+ &mt('Comparison of student IDs: [_1] matching ([quant,_2,entry,entries])',
+ ''.$showpct.' ',$found_match_count)).' '.
+ &mt('Comparison of student IDs in the uploaded file with'.
+ ' the course roster found matches for [_1] of the [_2] entries'.
+ ' in the file (for the format defined for [_3]).',
+ ''.$showpct.' ',''.$max_match_count.' ',$format_descs);
+ } else {
+ # Not all entries matching? -> Show warning and additional info
+ $output .=
+ &Apache::lonhtmlcommon::confirm_success(
+ &mt('Comparison of student IDs: [_1] matching ([_2]/[quant,_3,entry,entries])',
+ ''.$showpct.' ',$found_match_count,$max_match_count).' '.
+ &mt('Not all entries could be matched!'),1).' '.
+ &mt('Comparison of student IDs in the uploaded file with'.
+ ' the course roster found matches for [_1] of the [_2] entries'.
+ ' in the file (for the format defined for [_3]).',
+ ''.$showpct.' ',''.$max_match_count.' ',$format_descs).
+ ''.
+ &mt('A low percentage of matches results from one of the following:').
+ '
'.
+ ''.&mt('The file was uploaded to the wrong course.').' '.
+ ''.&mt('The data is not in the format expected for the domain: [_1]',
+ ''.$cdom.' ').' '.
+ ''.&mt('Students did not bubble their IDs, or mis-bubbled them').' '.
+ ''.&mt('The course roster is not up to date.').' '.
+ ' ';
+ }
}
} else {
- $output = ''.&mt('Uploaded file contained no data').' ';
+ $output = ''.&mt('Uploaded file contained no data').'
';
}
return $output;
}
@@ -8332,18 +8856,17 @@ sub valid_file {
}
sub scantron_download_scantron_data {
- my ($r)=@_;
- my $default_form_data=&defaultFormData(&get_symb($r,1));
+ my ($r,$symb)=@_;
+ my $default_form_data=&defaultFormData($symb);
my $cname=$env{'course.'.$env{'request.course.id'}.'.num'};
my $cdom=$env{'course.'.$env{'request.course.id'}.'.domain'};
my $file=$env{'form.scantron_selectfile'};
if (! &valid_file($file)) {
$r->print('
- '.&mt('The requested file name was invalid.').'
+ '.&mt('The requested filename was invalid.').'
');
- $r->print(&show_grading_menu_form(&get_symb($r,1)));
return;
}
my $orig='/uploaded/'.$cdom.'/'.$cname.'/scantron_orig_'.$file;
@@ -8354,7 +8877,7 @@ sub scantron_download_scantron_data {
&Apache::lonnet::allowuploaded('/adm/grades',$skipped);
$r->print('
- '.&mt('[_1]Original[_2] file as uploaded by the scantron office.',
+ '.&mt('[_1]Original[_2] file as uploaded by the bubblesheet office.',
'',' ').'
@@ -8366,15 +8889,12 @@ sub scantron_download_scantron_data {
'',' ').'
');
- $r->print(&show_grading_menu_form(&get_symb($r,1)));
return '';
}
sub checkscantron_results {
- my ($r) = @_;
- my ($symb)=&get_symb($r);
+ my ($r,$symb) = @_;
if (!$symb) {return '';}
- my $grading_menu_button=&show_grading_menu_form($symb);
my $cid = $env{'request.course.id'};
my %lettdig = &letter_to_digits();
my $numletts = scalar(keys(%lettdig));
@@ -8384,6 +8904,7 @@ sub checkscantron_results {
my %record;
my %scantron_config =
&Apache::grades::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();
my %idmap=&Apache::grades::username_to_idmap($classlist);
@@ -8393,10 +8914,20 @@ sub checkscantron_results {
return '';
}
my $map=$navmap->getResourceByUrl($sequence);
+ my ($randomorder,$randompick,@master_seq,%symb_to_resource,%grader_partids_by_symb,
+ %grader_randomlists_by_symb,%orderedforcode);
+ if (ref($map)) {
+ $randomorder=$map->randomorder();
+ $randompick=$map->randompick();
+ }
my @resources=$navmap->retrieveResources($map,\&scantron_filter,1,0);
- my (%grader_partids_by_symb,%grader_randomlists_by_symb);
- &graders_resources_pass(\@resources,\%grader_partids_by_symb, \%grader_randomlists_by_symb);
-
+ my $nav_error = &get_master_seq(\@resources,\@master_seq,\%symb_to_resource);
+ if ($nav_error) {
+ $r->print(&navmap_errormsg());
+ return '';
+ }
+ &graders_resources_pass(\@resources,\%grader_partids_by_symb,
+ \%grader_randomlists_by_symb,$bubbles_per_row);
my ($uname,$udom);
my (%scandata,%lastname,%bylast);
$r->print('
@@ -8405,20 +8936,16 @@ sub checkscantron_results {
my @delayqueue;
my %completedstudents;
- my $count=&Apache::grades::get_todo_count($scanlines,$scan_data);
- my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin($r,'Bubblesheet/Submissions Comparison Status',
- 'Progress of Bubblesheet Data/Submission Records Comparison',$count,
- 'inline',undef,'checkscantron');
+ my $count=&get_todo_count($scanlines,$scan_data);
+ my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin($r,$count);
my ($username,$domain,$started);
- my $nav_error;
&scantron_get_maxbubble(\$nav_error,\%scantron_config); # Need the bubble lines array to parse.
if ($nav_error) {
$r->print(&navmap_errormsg());
return '';
}
- &Apache::lonhtmlcommon::Update_PrgWin($r,\%prog_state,
- 'Processing first student');
+ &Apache::lonhtmlcommon::Update_PrgWin($r,\%prog_state,'Processing first student');
my $start=&Time::HiRes::time();
my $i=-1;
@@ -8428,15 +8955,14 @@ sub checkscantron_results {
my $line=&Apache::grades::scantron_get_line($scanlines,$scan_data,$i);
if ($line=~/^[\s\cz]*$/) { next; }
if ($started) {
- &Apache::lonhtmlcommon::Increment_PrgWin($r,\%prog_state,
- 'last student');
+ &Apache::lonhtmlcommon::Increment_PrgWin($r,\%prog_state,'last student');
}
$started=1;
my $scan_record=
&Apache::grades::scantron_parse_scanline($line,$i,\%scantron_config,
$scan_data);
- unless ($uname=&Apache::grades::scantron_find_student($scan_record,$scan_data,
- \%idmap,$i)) {
+ unless ($uname=&scantron_find_student($scan_record,$scan_data,
+ \%idmap,$i)) {
&Apache::grades::scantron_add_delay(\@delayqueue,$line,
'Unable to find a student that matches',1);
next;
@@ -8449,13 +8975,40 @@ sub checkscantron_results {
my $pid = $scan_record->{'scantron.ID'};
$lastname{$pid} = $scan_record->{'scantron.LastName'};
push(@{$bylast{$lastname{$pid}}},$pid);
+ my $usec = $classlist->{$uname}->[&Apache::loncoursedata::CL_SECTION];
+ my $user = $uname.':'.$usec;
+ ($username,$domain)=split(/:/,$uname);
+
+ my $scancode;
+ if ((exists($scan_record->{'scantron.CODE'})) &&
+ (&Apache::lonnet::validCODE($scan_record->{'scantron.CODE'}))) {
+ $scancode = $scan_record->{'scantron.CODE'};
+ } else {
+ $scancode = '';
+ }
+
+ my @mapresources = @resources;
my $lastpos = $env{'form.scantron_maxbubble'}*$scantron_config{'Qlength'};
+ my %respnumlookup=();
+ my %startline=();
+ if ($randomorder || $randompick) {
+ @mapresources =
+ &users_order($user,$scancode,$sequence,\@master_seq,\%symb_to_resource,
+ \%orderedforcode);
+ my $total = &get_respnum_lookups($sequence,$scan_data,\%idmap,$line,
+ $scan_record,\@master_seq,\%symb_to_resource,
+ \%grader_partids_by_symb,\%orderedforcode,
+ \%respnumlookup,\%startline);
+ if ($randompick && $total) {
+ $lastpos = $total*$scantron_config{'Qlength'};
+ }
+ }
$scandata{$pid} = substr($line,$scantron_config{'Qstart'}-1,$lastpos);
chomp($scandata{$pid});
$scandata{$pid} =~ s/\r$//;
- ($username,$domain)=split(/:/,$uname);
+
my $counter = -1;
- foreach my $resource (@resources) {
+ foreach my $resource (@mapresources) {
my $parts;
my $ressymb = $resource->symb();
if ((exists($grader_randomlists_by_symb{$ressymb})) ||
@@ -8470,7 +9023,9 @@ sub checkscantron_results {
($counter,my $recording) =
&verify_scantron_grading($resource,$domain,$username,$cid,$counter,
$scandata{$pid},$parts,
- \%scantron_config,\%lettdig,$numletts);
+ \%scantron_config,\%lettdig,$numletts,
+ $randomorder,$randompick,
+ \%respnumlookup,\%startline);
$record{$pid} .= $recording;
}
}
@@ -8508,15 +9063,21 @@ sub checkscantron_results {
}
}
}
- $r->print(''.
- &mt('Comparison of bubblesheet data (including corrections) with corresponding submission records (most recent submission) for [_1][quant,_2,student][_3] ([quant,_4,bubblesheet line] per student).',
- '',
- $numstudents,
- ' ',
- $env{'form.scantron_maxbubble'}).
- '
'
+ $r->print(
+ ''
+ .&mt('Comparison of bubblesheet data (including corrections) with corresponding submission records (most recent submission) for [_1][quant,_2,student][_3] ([quant,_4,bubblesheet line] per student).',
+ '',
+ $numstudents,
+ ' ',
+ $env{'form.scantron_maxbubble'})
+ .'
'
+ );
+ $r->print(''
+ .&mt('Exact matches for [_1][quant,_2,student][_3].','',$passed,' ')
+ .' '
+ .&mt('Discrepancies detected for [_1][quant,_2,student][_3].','',$failed,' ')
+ .'
'
);
- $r->print(''.&mt('Exact matches for [quant,_1,student] .',$passed).' '.&mt('Discrepancies detected for [quant,_1,student] .',$failed).'
');
if ($passed) {
$r->print(&mt('Students with exact correspondence between bubblesheet data and submissions are as follows:').' ');
$r->print(&Apache::loncommon::start_data_table()."\n".
@@ -8536,13 +9097,14 @@ sub checkscantron_results {
&Apache::loncommon::end_data_table()).' '.
&mt('Differences can occur if submissions were modified using manual grading after a bubblesheet grading pass.').' '.&mt('If unexpected discrepancies were detected, it is recommended that you inspect the original bubblesheets.');
}
- $r->print(' '.$grading_menu_button);
+ $r->print(' ');
return;
}
sub verify_scantron_grading {
my ($resource,$domain,$username,$cid,$counter,$scandata,$partids,
- $scantron_config,$lettdig,$numletts) = @_;
+ $scantron_config,$lettdig,$numletts,$randomorder,$randompick,
+ $respnumlookup,$startline) = @_;
my ($record,%expected,%startpos);
return ($counter,$record) if (!ref($resource));
return ($counter,$record) if (!$resource->is_problem());
@@ -8551,15 +9113,21 @@ sub verify_scantron_grading {
foreach my $part_id (@{$partids}) {
$counter ++;
$expected{$part_id} = 0;
- if ($env{"form.scantron.sub_bubblelines.$counter"}) {
- my @sub_lines = split(/,/,$env{"form.scantron.sub_bubblelines.$counter"});
+ my $respnum = $counter;
+ if ($randomorder || $randompick) {
+ $respnum = $respnumlookup->{$counter};
+ $startpos{$part_id} = $startline->{$counter} + 1;
+ } else {
+ $startpos{$part_id} = $env{"form.scantron.first_bubble_line.$counter"};
+ }
+ if ($env{"form.scantron.sub_bubblelines.$respnum"}) {
+ my @sub_lines = split(/,/,$env{"form.scantron.sub_bubblelines.$respnum"});
foreach my $item (@sub_lines) {
$expected{$part_id} += $item;
}
} else {
- $expected{$part_id} = $env{"form.scantron.bubblelines.$counter"};
+ $expected{$part_id} = $env{"form.scantron.bubblelines.$respnum"};
}
- $startpos{$part_id} = $env{"form.scantron.first_bubble_line.$counter"};
}
if ($symb) {
my %recorded;
@@ -8655,7 +9223,7 @@ sub verify_scantron_grading {
return ($counter,$record);
}
-sub letter_to_digits {
+sub letter_to_digits {
my %lettdig = (
A => 1,
B => 2,
@@ -8678,48 +9246,34 @@ sub letter_to_digits {
#-------------------------- Menu interface -------------------------
#
-#--- Show a Grading Menu button - Calls the next routine ---
-sub show_grading_menu_form {
- my ($symb)=@_;
- my $result.=''."\n".
- ' '."\n".
- ' '."\n".
- ' '."\n".
- ' '."\n".
- ' '."\n";
- return $result;
-}
+#--- Href with symb and command ---
-# -- Retrieve choices for grading form
-sub savedState {
- my %savedState = ();
- if ($env{'form.saveState'}) {
- foreach (split(/:/,$env{'form.saveState'})) {
- my ($key,$value) = split(/=/,$_,2);
- $savedState{$key} = $value;
- }
- }
- return \%savedState;
+sub href_symb_cmd {
+ my ($symb,$cmd)=@_;
+ return '/adm/grades?symb='.&HTML::Entities::encode(&Apache::lonenc::check_encrypt($symb),'<>&"').'&command='.$cmd;
}
sub grading_menu {
- my ($request) = @_;
- my ($symb)=&get_symb($request);
+ my ($request,$symb) = @_;
if (!$symb) {return '';}
- my $probTitle = &Apache::lonnet::gettitle($symb);
- my ($table,undef,$hdgrade) = &showResourceInfo($symb,$probTitle);
- $request->print($table);
my %fields = ('symb'=>&Apache::lonenc::check_encrypt($symb),
- 'handgrade'=>$hdgrade,
- 'probTitle'=>$probTitle,
- 'command'=>'submit_options',
- 'saveState'=>"",
- 'gradingMenu'=>1,
- 'showgrading'=>"yes");
-
- my $url1 = &Apache::lonhtmlcommon::build_url('grades/',\%fields);
+ 'command'=>'individual');
+ my $url1a = &Apache::lonhtmlcommon::build_url('grades/',\%fields);
+
+ $fields{'command'}='ungraded';
+ my $url1b=&Apache::lonhtmlcommon::build_url('grades/',\%fields);
+
+ $fields{'command'}='table';
+ my $url1c=&Apache::lonhtmlcommon::build_url('grades/',\%fields);
+
+ $fields{'command'}='all_for_one';
+ my $url1d=&Apache::lonhtmlcommon::build_url('grades/',\%fields);
+
+ $fields{'command'}='downloadfilesselect';
+ my $url1e=&Apache::lonhtmlcommon::build_url('grades/',\%fields);
+
$fields{'command'} = 'csvform';
my $url2 = &Apache::lonhtmlcommon::build_url('grades/',\%fields);
@@ -8728,15 +9282,46 @@ sub grading_menu {
$fields{'command'} = 'scantron_selectphase';
my $url4 = &Apache::lonhtmlcommon::build_url('grades/',\%fields);
+
+ $fields{'command'} = 'initialverifyreceipt';
+ my $url5 = &Apache::lonhtmlcommon::build_url('grades/',\%fields);
- my @menu = ({ categorytitle=>'Course Grading',
+ my @menu = ({ categorytitle=>'Hand Grading',
items =>[
- { linktext => 'Manual Grading/View Submissions',
- url => $url1,
+ { linktext => 'Select individual students to grade',
+ url => $url1a,
permission => 'F',
- icon => 'edit-find-replace.png',
- linktitle => 'Start the process of hand grading submissions.'
+ icon => 'grade_students.png',
+ linktitle => 'Grade current resource for a selection of students.'
+ },
+ { linktext => 'Grade ungraded submissions.',
+ url => $url1b,
+ permission => 'F',
+ icon => 'ungrade_sub.png',
+ linktitle => 'Grade all submissions that have not been graded yet.'
+ },
+
+ { linktext => 'Grading table',
+ url => $url1c,
+ permission => 'F',
+ icon => 'grading_table.png',
+ linktitle => 'Grade current resource for all students.'
+ },
+ { linktext => 'Grade page/folder for one student',
+ url => $url1d,
+ permission => 'F',
+ icon => 'grade_PageFolder.png',
+ linktitle => 'Grade all resources in current page/sequence/folder for one student.'
},
+ { linktext => 'Download submissions',
+ url => $url1e,
+ permission => 'F',
+ icon => 'download_sub.png',
+ linktitle => 'Download all students submissions.'
+ }]},
+ { categorytitle=>'Automated Grading',
+ items =>[
+
{ linktext => 'Upload Scores',
url => $url2,
permission => 'F',
@@ -8752,168 +9337,132 @@ sub grading_menu {
{ linktext => 'Grade/Manage/Review Bubblesheets',
url => $url4,
permission => 'F',
- icon => 'stat.png',
+ icon => 'bubblesheet.png',
linktitle => 'Grade bubblesheet exams, upload/download bubblesheet data files, and review previously graded bubblesheet exams.'
- }
+ },
+ { linktext => 'Verify Receipt Number',
+ url => $url5,
+ permission => 'F',
+ icon => 'receipt_number.png',
+ linktitle => 'Verify a system-generated receipt number for correct problem solution.'
+ }
+
]
});
- #$fields{'command'} = 'verify';
- #$url = &Apache::lonhtmlcommon::build_url('grades/',\%fields);
- #
# Create the menu
my $Str;
- # $Str .= ''.&mt('Please select a grading task').' ';
$Str .= '';
$Str .= ' '.
- ' '."\n".
- ' '."\n".
- ' '."\n".
- ' '."\n".
- ' '."\n".
- ' '."\n";
-
- $Str .= Apache::lonhtmlcommon::generate_menu(@menu);
- #$menudata->{'jscript'}
- $Str .=' '.
- &Apache::lonnet::recprefix($env{'request.course.id'}).
- '- ';
+ ' '."\n";
- $Str .=" \n";
- my $receiptalert = &mt("Please enter a receipt number given by a student in the receipt box.");
- $request->print(<
- function checkChoice(formname,val,cmdx) {
- if (val <= 2) {
- var cmd = radioSelection(formname.radioChoice);
- var cmdsave = cmd;
- } else {
- cmd = cmdx;
- cmdsave = 'submission';
- }
- formname.command.value = cmd;
- if (val < 5) formname.submit();
- if (val == 5) {
- if (!checkReceiptNo(formname,'notOK')) {
- return false;
- } else {
- formname.submit();
- }
- }
- }
+ $Str .= &Apache::lonhtmlcommon::generate_menu(@menu);
+ return $Str;
+}
- function checkReceiptNo(formname,nospace) {
- var receiptNo = formname.receipt.value;
- var checkOpt = false;
- if (nospace == "OK" && isNaN(receiptNo)) {checkOpt = true;}
- if (nospace == "notOK" && (isNaN(receiptNo) || receiptNo == "")) {checkOpt = true;}
- if (checkOpt) {
- alert("$receiptalert");
- formname.receipt.value = "";
- formname.receipt.focus();
- return false;
- }
- return true;
- }
-
-GRADINGMENUJS
+
+sub ungraded {
+ my ($request)=@_;
+ &submit_options($request);
+}
+
+sub submit_options_sequence {
+ my ($request,$symb) = @_;
+ if (!$symb) {return '';}
&commonJSfunctions($request);
- return $Str;
+ my $result;
+
+ $result.=''."\n".
+ ' '."\n";
+ $result.=&selectfield(0).
+ '
+
+
+
+
+ ';
+ return $result;
}
+sub submit_options_table {
+ my ($request,$symb) = @_;
+ if (!$symb) {return '';}
+ &commonJSfunctions($request);
+ my $result;
+
+ $result.=''."\n".
+ ' '."\n";
+
+ $result.=&selectfield(0).
+ '
+
+
+
+
+ ';
+ return $result;
+}
+
+sub submit_options_download {
+ my ($request,$symb) = @_;
+ if (!$symb) {return '';}
+
+ &commonJSfunctions($request);
+
+ my $result=''."\n".
+ ' '."\n";
+ $result.='
+
+ '.&mt('Select Students for Which to Download Submissions').'
+ '.&selectfield(1).'
+
+
+
+
+
+
+ ';
+ return $result;
+}
#--- Displays the submissions first page -------
sub submit_options {
- my ($request) = @_;
- my ($symb)=&get_symb($request);
+ my ($request,$symb) = @_;
if (!$symb) {return '';}
- my $probTitle = &Apache::lonnet::gettitle($symb);
- my $receiptalert = &mt("Please enter a receipt number given by a student in the receipt box.");
- $request->print(<
- function checkChoice(formname,val,cmdx) {
- if (val <= 2) {
- var cmd = radioSelection(formname.radioChoice);
- var cmdsave = cmd;
- } else {
- cmd = cmdx;
- cmdsave = 'submission';
- }
- formname.command.value = cmd;
- formname.saveState.value = "saveCmd="+cmdsave+":saveSec="+pullDownSelection(formname.section)+
- ":saveSub="+pullDownSelection(formname.submitonly)+":saveStatus="+pullDownSelection(formname.Status);
- if (val < 5) formname.submit();
- if (val == 5) {
- if (!checkReceiptNo(formname,'notOK')) { return false;}
- formname.submit();
- }
- if (val < 7) formname.submit();
- }
-
- function checkReceiptNo(formname,nospace) {
- var receiptNo = formname.receipt.value;
- var checkOpt = false;
- if (nospace == "OK" && isNaN(receiptNo)) {checkOpt = true;}
- if (nospace == "notOK" && (isNaN(receiptNo) || receiptNo == "")) {checkOpt = true;}
- if (checkOpt) {
- alert("$receiptalert");
- formname.receipt.value = "";
- formname.receipt.focus();
- return false;
- }
- return true;
- }
-
-GRADINGMENUJS
&commonJSfunctions($request);
- my ($table,undef,$hdgrade) = &showResourceInfo($symb,$probTitle);
my $result;
- my (undef,$sections) = &getclasslist('all','0');
- my $savedState = &savedState();
- my $saveCmd = ($$savedState{'saveCmd'} eq '' ? 'submission' : $$savedState{'saveCmd'});
- my $saveSec = ($$savedState{'saveSec'} eq '' ? 'all' : $$savedState{'saveSec'});
- my $saveSub = ($$savedState{'saveSub'} eq '' ? 'all' : $$savedState{'saveSub'});
- my $saveStatus = ($$savedState{'saveStatus'} eq '' ? 'Active' : $$savedState{'saveStatus'});
-
- # Preselect sections
- my $selsec="";
- if (ref($sections)) {
- foreach my $section (sort(@$sections)) {
- $selsec.=''.$section.' '."\n";
- }
- }
$result.=''."\n".
- ' '."\n".
- ' '."\n".
- ' '."\n".
- ' '."\n".
- ' '."\n".
- ' '."\n".
- ' '."\n";
+ ' '."\n";
+ $result.=&selectfield(1).'
+
+
+
+
- $result.='
-
- '.&mt('Grade Current Resource').'
-
-
- '.$table.'
-
-
+ ';
+ return $result;
+}
+
+sub selectfield {
+ my ($full)=@_;
+ my %options =
+ (&Apache::lonlocal::texthash(
+ 'yes' => 'with submissions',
+ 'queued' => 'in grading queue',
+ 'graded' => 'with ungraded submissions',
+ 'incorrect' => 'with incorrect submissions',
+ 'all' => 'with any status'),
+ 'select_form_order' => ['yes','queued','graded','incorrect','all']);
+ my $result='
'.&mt('Sections').'
- '."\n";
- $result.= $selsec;
- $result.= 'all ';
- $result.='
+ '.&Apache::lonstatistics::SectionSelect('section','multiple',5).'
@@ -8927,63 +9476,18 @@ GRADINGMENUJS
'.&mt('Access Status').'
- '.&Apache::lonhtmlcommon::StatusOptions($saveStatus,undef,5,undef,'mult').'
-
-
+ '.&Apache::lonhtmlcommon::StatusOptions(undef,undef,5,undef,'mult').'
+ ';
+ if ($full) {
+ $result.='
'.&mt('Submission Status').'
-
-
- '.&mt('with submissions').'
- '.&mt('in grading queue').'
- '.&mt('with ungraded submissions').'
- '.&mt('with incorrect submissions').'
- '.&mt('with any status').'
-
-
-
-
-
-
-
-
-
-
- '.&mt('Grade Complete Folder for One Student').'
-
-
- ';
- $result .= &show_grading_menu_form($symb);
+ '.
+ &Apache::loncommon::select_form('all','submitonly',\%options).
+ '';
+ }
+ $result.='
';
return $result;
}
@@ -9009,6 +9513,21 @@ sub init_perm {
}
}
+sub init_old_essays {
+ my ($symb,$apath,$adom,$aname) = @_;
+ if ($symb ne '') {
+ my %essays = &Apache::lonnet::dump('nohist_essay_'.$apath,$adom,$aname);
+ if (keys(%essays) > 0) {
+ $old_essays{$symb} = \%essays;
+ }
+ }
+ return;
+}
+
+sub reset_old_essays {
+ undef(%old_essays);
+}
+
sub gather_clicker_ids {
my %clicker_ids;
@@ -9071,18 +9590,14 @@ sub clicker_grading_parameters {
}
sub process_clicker {
- my ($r)=@_;
- my ($symb)=&get_symb($r);
+ my ($r,$symb)=@_;
if (!$symb) {return '';}
my $result=&checkforfile_js();
- $env{'form.probTitle'} = &Apache::lonnet::gettitle($symb);
- my ($table) = &showResourceInfo($symb,$env{'form.probTitle'});
- $result.=$table;
- $result.=''."\n";
- $result.=''."\n";
- $result.=' '.&mt('Specify a file containing the clicker information for this resource.').
- ' '."\n";
- $result.=''."\n";
+ $result.=&Apache::loncommon::start_data_table().
+ &Apache::loncommon::start_data_table_header_row().
+ ' '.&mt('Specify a file containing clicker information and set grading options.').' '.
+ &Apache::loncommon::end_data_table_header_row().
+ &Apache::loncommon::start_data_table_row()."\n";
# Attempt to restore parameters from last session, set defaults if not present
my %Saveable_Parameters=&clicker_grading_parameters();
&Apache::loncommon::restore_course_settings('grades_clicker',
@@ -9099,7 +9614,7 @@ sub process_clicker {
}
}
- my $upload=&mt("Upload File");
+ my $upload=&mt("Evaluate File");
my $type=&mt("Type");
my $attendance=&mt("Award points just for participation");
my $personnel=&mt("Correctness determined from response by course personnel");
@@ -9109,11 +9624,11 @@ sub process_clicker {
my $pcorrect=&mt("Percentage points for correct solution");
my $pincorrect=&mt("Percentage points for incorrect solution");
my $selectform=&Apache::loncommon::select_form($env{'form.upfiletype'},'upfiletype',
- {'iclicker' => 'i>clicker',
- 'interwrite' => 'interwrite PRS'});
+ {'iclicker' => 'i>clicker',
+ 'interwrite' => 'interwrite PRS',
+ 'turning' => 'Turning Technologies'});
$symb = &Apache::lonenc::check_encrypt($symb);
- $result.=<
+ $result.= &Apache::lonhtmlcommon::scripttag(<
+ENDUPFORM
+ $result.= <
-
-
$type: $selectform
- $attendance
+ENDUPFORM
+ $result.=' '.&Apache::loncommon::end_data_table_row().
+ &Apache::loncommon::start_data_table_row().''.(< $attendance
$personnel
$specific
@@ -9167,34 +9684,35 @@ function sanitycheck() {
-$pcorrect:
+ENDGRADINGFORM
+ $result.=' '.&Apache::loncommon::end_data_table_row().
+ &Apache::loncommon::start_data_table_row().''.(<$pcorrect:
$pincorrect:
-
-ENDUPFORM
- $result.='
'."\n".
- '
'."\n";
- $result.=&show_grading_menu_form($symb);
+ '
+ENDPERCFORM
+ $result.=' '.
+ &Apache::loncommon::end_data_table_row().
+ &Apache::loncommon::end_data_table();
return $result;
}
sub process_clicker_file {
- my ($r)=@_;
- my ($symb)=&get_symb($r);
+ my ($r,$symb)=@_;
if (!$symb) {return '';}
my %Saveable_Parameters=&clicker_grading_parameters();
&Apache::loncommon::store_course_settings('grades_clicker',
\%Saveable_Parameters);
-
- my ($result) = &showResourceInfo($symb,$env{'form.probTitle'});
+ my $result='';
if (($env{'form.gradingmechanism'} eq 'specific') && ($env{'form.specificid'}!~/\w/)) {
$result.=''.&mt('You need to specify a clicker ID for the correct answer').' ';
- return $result.&show_grading_menu_form($symb);
+ return $result;
}
if (($env{'form.gradingmechanism'} eq 'given') && ($env{'form.givenanswer'}!~/\S/)) {
$result.=''.&mt('You need to specify the correct answer').' ';
- return $result.&show_grading_menu_form($symb);
+ return $result;
}
my $foundgiven=0;
if ($env{'form.gradingmechanism'} eq 'given') {
@@ -9239,33 +9757,34 @@ sub process_clicker_file {
$number++;
}
$result.="\n";
- if ($number==0) {
- $result.=''.&mt('No IDs found to determine correct answer').' ';
- return $result.&show_grading_menu_form($symb);
- }
+ if ($number==0) {
+ $result .=
+ &Apache::lonhtmlcommon::confirm_success(
+ &mt('No IDs found to determine correct answer'),1);
+ return $result;
+ }
}
if (length($env{'form.upfile'}) < 2) {
- $result.=&mt('[_1] Error: [_2] The file you attempted to upload, [_3] contained no information. Please check that you entered the correct filename.',
- '',
- ' ',
- ''.&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"').' ');
- return $result.&show_grading_menu_form($symb);
+ $result .=
+ &Apache::lonhtmlcommon::confirm_success(
+ &mt('The file: [_1] you attempted to upload contained no information. Please check that you entered the correct filename.',
+ ''.&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"').' '),1);
+ return $result;
}
# Were able to get all the info needed, now analyze the file
$result.=&Apache::loncommon::studentbrowser_javascript();
$symb = &Apache::lonenc::check_encrypt($symb);
- my $heading=&mt('Scanning clicker file');
- $result.=(<
-
-$heading
+ $result.=&Apache::loncommon::start_data_table().
+ &Apache::loncommon::start_data_table_header_row().
+ ' '.&mt('Evaluate clicker file').' '.
+ &Apache::loncommon::end_data_table_header_row().
+ &Apache::loncommon::start_data_table_row().(<
-
-
@@ -9283,6 +9802,9 @@ ENDHEADER
if ($env{'form.upfiletype'} eq 'interwrite') {
($errormsg,$number)=&interwrite_eval(\@questiontitles,\%responses);
}
+ if ($env{'form.upfiletype'} eq 'turning') {
+ ($errormsg,$number)=&turning_eval(\@questiontitles,\%responses);
+ }
$result.=' '.&mt('Found [_1] question(s)',$number).' '.
' '.
&mt('Awarding [_1] percent for correct and [_2] percent for incorrect responses',
@@ -9290,7 +9812,7 @@ ENDHEADER
' ';
if (($env{'form.gradingmechanism'} eq 'given') && ($number!=$foundgiven)) {
$result.=''.&mt('Number of given answers does not agree with number of questions in file.').' ';
- return $result.&show_grading_menu_form($symb);
+ return $result;
}
# Remember Question Titles
# FIXME: Possibly need delimiter other than ":"
@@ -9310,7 +9832,9 @@ ENDHEADER
} elsif ($clicker_ids{$id}) {
if ($clicker_ids{$id}=~/\,/) {
# More than one user with the same clicker!
- $result.="\n ".&mt('Clicker registered more than once').": ".$id." ";
+ $result.="".&Apache::loncommon::end_data_table_row().
+ &Apache::loncommon::start_data_table_row()."".
+ &mt('Clicker registered more than once').": ".$id." ";
$result.="\n".' '.
"";
foreach my $reguser (sort(split(/\,/,$clicker_ids{$id}))) {
@@ -9324,7 +9848,9 @@ ENDHEADER
$student_count++;
}
} else {
- $result.="\n ".&mt('Unregistered Clicker')." ".$id." ";
+ $result.=" ".&Apache::loncommon::end_data_table_row().
+ &Apache::loncommon::start_data_table_row()."".
+ &mt('Unregistered Clicker')." ".$id." ";
$result.="\n".' '.
"\n".&mt("Username").": ".
"\n".&mt("Domain").": ".
@@ -9337,7 +9863,7 @@ ENDHEADER
&mt('Found [_1] registered and [_2] unregistered clickers.',$student_count,$unknown_count);
if (($env{'form.gradingmechanism'} ne 'attendance') && ($env{'form.gradingmechanism'} ne 'given')) {
if ($correct_count==0) {
- $errormsg.="Found no correct answers answers for grading!";
+ $errormsg.="Found no correct answers for grading!";
} elsif ($correct_count>1) {
$result.=''.&mt("Found [_1] entries for grading!",$correct_count).' ';
}
@@ -9350,9 +9876,10 @@ ENDHEADER
} else {
$result.=' ';
}
- $result.='
'."\n".
- '
'."\n";
- return $result.&show_grading_menu_form($symb);
+ $result.=''.
+ &Apache::loncommon::end_data_table_row().
+ &Apache::loncommon::end_data_table();
+ return $result;
}
sub iclicker_eval {
@@ -9414,9 +9941,34 @@ sub interwrite_eval {
return ($errormsg,$number);
}
+sub turning_eval {
+ my ($questiontitles,$responses)=@_;
+ my $number=0;
+ my $errormsg='';
+ foreach my $line (split(/[\n\r]/,$env{'form.upfile'})) {
+ my %components=&Apache::loncommon::record_sep($line);
+ my @entries=map {$components{$_}} (sort(keys(%components)));
+ if ($#entries>$number) { $number=$#entries; }
+ my $id=$entries[0];
+ my @idresponses;
+ $id=~s/^[\#0]+//;
+ unless ($id) { next; }
+ for (my $idx=1;$idx<=$#entries;$idx++) {
+ $entries[$idx]=~s/\,/\;/g;
+ $entries[$idx]=~s/[^a-zA-Z0-9\.\*\-\+\;]+//g;
+ push(@idresponses,$entries[$idx]);
+ }
+ $$responses{$id}=join(',',@idresponses);
+ }
+ for (my $i=1; $i<=$number; $i++) {
+ $$questiontitles[$i]=&mt('Question [_1]',$i);
+ }
+ return ($errormsg,$number);
+}
+
+
sub assign_clicker_grades {
- my ($r)=@_;
- my ($symb)=&get_symb($r);
+ my ($r,$symb)=@_;
if (!$symb) {return '';}
# See which part we are saving to
my $res_error;
@@ -9427,15 +9979,11 @@ sub assign_clicker_grades {
# FIXME: This should probably look for the first handgradeable part
my $part=$$partlist[0];
# Start screen output
- my ($result) = &showResourceInfo($symb,$env{'form.probTitle'});
-
- $result .= ' '.
- &Apache::loncommon::start_data_table().
- &Apache::loncommon::start_data_table_header_row().
- ''.&mt('Assigning grades based on clicker file').' '.
- &Apache::loncommon::end_data_table_header_row().
- &Apache::loncommon::start_data_table_row().'';
-
+ my $result=&Apache::loncommon::start_data_table().
+ &Apache::loncommon::start_data_table_header_row().
+ ' '.&mt('Assigning grades based on clicker file').' '.
+ &Apache::loncommon::end_data_table_header_row().
+ &Apache::loncommon::start_data_table_row().'';
# Get correct result
# FIXME: Possibly need delimiter other than ":"
my @correct=();
@@ -9487,17 +10035,17 @@ sub assign_clicker_grades {
if ($user) {
if ($users{$user}) {
$result.=''.
- &mt("More than one entry found for [_1] !",$user).
+ &mt('More than one entry found for [_1]!',''.$user.' ').
' ';
}
- $users{$user}=1;
+ $users{$user}=1;
my @answer=split(/\,/,$env{$key});
my $sum=0;
my $realnumber=$number;
for (my $i=0;$i<$number;$i++) {
if ($correct[$i] eq '-') {
$realnumber--;
- } elsif ($answer[$i]) {
+ } elsif (($answer[$i]) || ($answer[$i]=~/^[0\.]+$/)) {
if ($gradingmechanism eq 'attendance') {
$sum+=$pcorrect;
} elsif ($correct[$i] eq '*') {
@@ -9544,8 +10092,8 @@ sub assign_clicker_grades {
$result.=' '.&mt('Successfully stored grades for [quant,_1,student].',$storecount).
' '.
&Apache::loncommon::end_data_table_row().
- &Apache::loncommon::end_data_table()." \n";
- return $result.&show_grading_menu_form($symb);
+ &Apache::loncommon::end_data_table();
+ return $result;
}
sub navmap_errormsg {
@@ -9555,6 +10103,29 @@ sub navmap_errormsg {
'';
}
+sub startpage {
+ my ($r,$symb,$crumbs,$onlyfolderflag,$nodisplayflag,$stuvcurrent,$stuvdisp,$nomenu,$js) = @_;
+ if ($nomenu) {
+ $r->print(&Apache::loncommon::start_page("Student's Version",$js,{'only_body' => '1'}));
+ } else {
+ unshift(@$crumbs,{href=>&href_symb_cmd($symb,'gradingmenu'),text=>"Grading"});
+ $r->print(&Apache::loncommon::start_page('Grading',$js,
+ {'bread_crumbs' => $crumbs}));
+ &Apache::lonquickgrades::startGradeScreen($r,($env{'form.symb'}?'probgrading':'grading'));
+ }
+ unless ($nodisplayflag) {
+ $r->print(&Apache::lonhtmlcommon::resource_info_box($symb,$onlyfolderflag,$stuvcurrent,$stuvdisp));
+ }
+}
+
+sub select_problem {
+ my ($r)=@_;
+ $r->print(''.&mt('Select the problem or one of the problems you want to grade').' ');
+ $r->print(&Apache::lonstathelpers::problem_selector('.',undef,1));
+ $r->print(' ');
+ $r->print(' ');
+}
+
sub handler {
my $request=$_[0];
&reset_caches();
@@ -9565,147 +10136,213 @@ sub handler {
}
&Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'});
- my $symb=&get_symb($request,1);
+# see what command we need to execute
+
my @commands=&Apache::loncommon::get_env_multiple('form.command');
my $command=$commands[0];
+ &init_perm();
+ if (!$env{'request.course.id'}) {
+ unless ((&Apache::lonnet::allowed('usc',$env{'request.role.domain'})) &&
+ ($command =~ /^scantronupload/)) {
+ # Not in a course.
+ $env{'user.error.msg'}="/adm/grades::vgr:0:0:Cannot display grades page outside course context";
+ return HTTP_NOT_ACCEPTABLE;
+ }
+ } elsif (!%perm) {
+ $request->internal_redirect('/adm/quickgrades');
+ return OK;
+ }
+ &Apache::loncommon::content_type($request,'text/html');
+ $request->send_http_header;
+
if ($#commands > 0) {
&Apache::lonnet::logthis("grades got multiple commands ".join(':',@commands));
}
+# see what the symb is
+
+ my $symb=$env{'form.symb'};
+ unless ($symb) {
+ (my $url=$env{'form.url'}) =~ s-^https*://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;
+ $symb=&Apache::lonnet::symbread($url);
+ }
+ &Apache::lonenc::check_decrypt(\$symb);
+
$ssi_error = 0;
- my $brcrum = [{href=>"/adm/grades",text=>"Grading"}];
- my $start_page = &Apache::loncommon::start_page('Grading',undef,
- {'bread_crumbs' => $brcrum});
- if ($symb eq '' && $command eq '') {
- if ($env{'user.adv'}) {
- &Apache::loncommon::content_type($request,'text/html');
- $request->send_http_header;
- $request->print($start_page);
- if (($env{'form.codeone'}) && ($env{'form.codetwo'}) &&
- ($env{'form.codethree'})) {
- my $token=$env{'form.codeone'}.'*'.$env{'form.codetwo'}.'*'.
- $env{'form.codethree'};
- my ($tsymb,$tuname,$tudom,$tcrsid)=
- &Apache::lonnet::checkin($token);
- if ($tsymb) {
- my ($map,$id,$url)=&Apache::lonnet::decode_symb($tsymb);
- if (&Apache::lonnet::allowed('mgr',$tcrsid)) {
- $request->print(&ssi_with_retries('/res/'.$url, $ssi_retries,
- ('grade_username' => $tuname,
- 'grade_domain' => $tudom,
- 'grade_courseid' => $tcrsid,
- 'grade_symb' => $tsymb)));
- } else {
- $request->print('Not authorized: '.$token.' ');
- }
- } else {
- $request->print('Not a valid DocID: '.$token.' ');
- }
- } else {
- $request->print(&Apache::lonxml::tokeninputfield());
- }
- } elsif ($env{'request.course.id'}) {
- &init_perm();
- if (!%perm) {
- $request->internal_redirect('/adm/quickgrades');
- } else {
- &Apache::loncommon::content_type($request,'text/html');
- $request->send_http_header;
- $request->print($start_page);
- }
- }
+ if (($symb eq '' || $command eq '') && ($env{'request.course.id'})) {
+#
+# Not called from a resource, but inside a course
+#
+ &startpage($request,undef,[],1,1);
+ &select_problem($request);
} else {
- &init_perm();
- if (!$env{'request.course.id'}) {
- unless ((&Apache::lonnet::allowed('usc',$env{'request.role.domain'})) &&
- ($command =~ /^scantronupload/)) {
- # Not in a course.
- $env{'user.error.msg'}="/adm/grades::vgr:0:0:Cannot display grades page outside course context";
- return HTTP_NOT_ACCEPTABLE;
- }
- } elsif (!%perm) {
- $request->internal_redirect('/adm/quickgrades');
- }
- &Apache::loncommon::content_type($request,'text/html');
- $request->send_http_header;
- $request->print($start_page);
if ($command eq 'submission' && $perm{'vgr'}) {
- ($env{'form.student'} eq '' ? &listStudents($request) : &submission($request,0,0));
+ my ($stuvcurrent,$stuvdisp,$versionform,$js);
+ if (($env{'form.student'} ne '') && ($env{'form.userdom'} ne '')) {
+ ($stuvcurrent,$stuvdisp,$versionform,$js) =
+ &choose_task_version_form($symb,$env{'form.student'},
+ $env{'form.userdom'});
+ }
+ &startpage($request,$symb,[{href=>"", text=>"Student Submissions"}],undef,undef,$stuvcurrent,$stuvdisp,undef,$js);
+ if ($versionform) {
+ $request->print($versionform);
+ }
+ $request->print(' ');
+ ($env{'form.student'} eq '' ? &listStudents($request,$symb) : &submission($request,0,0,$symb));
+ } elsif ($command eq 'versionsub' && $perm{'vgr'}) {
+ my ($stuvcurrent,$stuvdisp,$versionform,$js) =
+ &choose_task_version_form($symb,$env{'form.student'},
+ $env{'form.userdom'},
+ $env{'form.inhibitmenu'});
+ &startpage($request,$symb,[{href=>"", text=>"Previous Student Version"}],undef,undef,$stuvcurrent,$stuvdisp,$env{'form.inhibitmenu'},$js);
+ if ($versionform) {
+ $request->print($versionform);
+ }
+ $request->print(' ');
+ $request->print(&show_previous_task_version($request,$symb));
} elsif ($command eq 'pickStudentPage' && $perm{'vgr'}) {
- &pickStudentPage($request);
+ &startpage($request,$symb,[{href=>&href_symb_cmd($symb,'all_for_one'),text=>'Grade page/folder for one student'},
+ {href=>'',text=>'Select student'}],1,1);
+ &pickStudentPage($request,$symb);
} elsif ($command eq 'displayPage' && $perm{'vgr'}) {
- &displayPage($request);
+ &startpage($request,$symb,
+ [{href=>&href_symb_cmd($symb,'all_for_one'),text=>'Grade page/folder for one student'},
+ {href=>'',text=>'Select student'},
+ {href=>'',text=>'Grade student'}],1,1);
+ &displayPage($request,$symb);
} elsif ($command eq 'gradeByPage' && $perm{'mgr'}) {
- &updateGradeByPage($request);
+ &startpage($request,$symb,[{href=>&href_symb_cmd($symb,'all_for_one'),text=>'Grade page/folder for one student'},
+ {href=>'',text=>'Select student'},
+ {href=>'',text=>'Grade student'},
+ {href=>'',text=>'Store grades'}],1,1);
+ &updateGradeByPage($request,$symb);
} elsif ($command eq 'processGroup' && $perm{'vgr'}) {
- &processGroup($request);
+ &startpage($request,$symb,[{href=>'',text=>'...'},
+ {href=>'',text=>'Modify grades'}]);
+ &processGroup($request,$symb);
} elsif ($command eq 'gradingmenu' && $perm{'vgr'}) {
- $request->print(&grading_menu($request));
- } elsif ($command eq 'submit_options' && $perm{'vgr'}) {
- $request->print(&submit_options($request));
+ &startpage($request,$symb);
+ $request->print(&grading_menu($request,$symb));
+ } elsif ($command eq 'individual' && $perm{'vgr'}) {
+ &startpage($request,$symb,[{href=>'',text=>'Select individual students to grade'}]);
+ $request->print(&submit_options($request,$symb));
+ } elsif ($command eq 'ungraded' && $perm{'vgr'}) {
+ &startpage($request,$symb,[{href=>'',text=>'Grade ungraded submissions'}]);
+ $request->print(&listStudents($request,$symb,'graded'));
+ } elsif ($command eq 'table' && $perm{'vgr'}) {
+ &startpage($request,$symb,[{href=>"", text=>"Grading table"}]);
+ $request->print(&submit_options_table($request,$symb));
+ } elsif ($command eq 'all_for_one' && $perm{'vgr'}) {
+ &startpage($request,$symb,[{href=>'',text=>'Grade page/folder for one student'}],1,1);
+ $request->print(&submit_options_sequence($request,$symb));
} elsif ($command eq 'viewgrades' && $perm{'vgr'}) {
- $request->print(&viewgrades($request));
+ &startpage($request,$symb,[{href=>&href_symb_cmd($symb,"table"), text=>"Grading table"},{href=>'', text=>"Modify grades"}]);
+ $request->print(&viewgrades($request,$symb));
} elsif ($command eq 'handgrade' && $perm{'mgr'}) {
- $request->print(&processHandGrade($request));
+ &startpage($request,$symb,[{href=>'',text=>'...'},
+ {href=>'',text=>'Store grades'}]);
+ $request->print(&processHandGrade($request,$symb));
} elsif ($command eq 'editgrades' && $perm{'mgr'}) {
- $request->print(&editgrades($request));
+ &startpage($request,$symb,[{href=>&href_symb_cmd($symb,"table"), text=>"Grading table"},
+ {href=>&href_symb_cmd($symb,'viewgrades').'&group=all§ion=all&Status=Active',
+ text=>"Modify grades"},
+ {href=>'', text=>"Store grades"}]);
+ $request->print(&editgrades($request,$symb));
+ } elsif ($command eq 'initialverifyreceipt' && $perm{'vgr'}) {
+ &startpage($request,$symb,[{href=>'',text=>'Verify Receipt Number'}]);
+ $request->print(&initialverifyreceipt($request,$symb));
} elsif ($command eq 'verify' && $perm{'vgr'}) {
- $request->print(&verifyreceipt($request));
+ &startpage($request,$symb,[{href=>&href_symb_cmd($symb,"initialverifyreceipt"),text=>'Verify Receipt Number'},
+ {href=>'',text=>'Verification Result'}]);
+ $request->print(&verifyreceipt($request,$symb));
} elsif ($command eq 'processclicker' && $perm{'mgr'}) {
- $request->print(&process_clicker($request));
+ &startpage($request,$symb,[{href=>'', text=>'Process clicker'}]);
+ $request->print(&process_clicker($request,$symb));
} elsif ($command eq 'processclickerfile' && $perm{'mgr'}) {
- $request->print(&process_clicker_file($request));
+ &startpage($request,$symb,[{href=>&href_symb_cmd($symb,'processclicker'), text=>'Process clicker'},
+ {href=>'', text=>'Process clicker file'}]);
+ $request->print(&process_clicker_file($request,$symb));
} elsif ($command eq 'assignclickergrades' && $perm{'mgr'}) {
- $request->print(&assign_clicker_grades($request));
+ &startpage($request,$symb,[{href=>&href_symb_cmd($symb,'processclicker'), text=>'Process clicker'},
+ {href=>'', text=>'Process clicker file'},
+ {href=>'', text=>'Store grades'}]);
+ $request->print(&assign_clicker_grades($request,$symb));
} elsif ($command eq 'csvform' && $perm{'mgr'}) {
- $request->print(&upcsvScores_form($request));
+ &startpage($request,$symb,[{href=>'', text=>'Upload Scores'}],1,1);
+ $request->print(&upcsvScores_form($request,$symb));
} elsif ($command eq 'csvupload' && $perm{'mgr'}) {
- $request->print(&csvupload($request));
+ &startpage($request,$symb,[{href=>'', text=>'Upload Scores'}],1,1);
+ $request->print(&csvupload($request,$symb));
} elsif ($command eq 'csvuploadmap' && $perm{'mgr'} ) {
- $request->print(&csvuploadmap($request));
+ &startpage($request,$symb,[{href=>'', text=>'Upload Scores'}],1,1);
+ $request->print(&csvuploadmap($request,$symb));
} elsif ($command eq 'csvuploadoptions' && $perm{'mgr'}) {
if ($env{'form.associate'} ne 'Reverse Association') {
- $request->print(&csvuploadoptions($request));
+ &startpage($request,$symb,[{href=>'', text=>'Upload Scores'}],1,1);
+ $request->print(&csvuploadoptions($request,$symb));
} else {
if ( $env{'form.upfile_associate'} ne 'reverse' ) {
$env{'form.upfile_associate'} = 'reverse';
} else {
$env{'form.upfile_associate'} = 'forward';
}
- $request->print(&csvuploadmap($request));
+ &startpage($request,$symb,[{href=>'', text=>'Upload Scores'}],1,1);
+ $request->print(&csvuploadmap($request,$symb));
}
} elsif ($command eq 'csvuploadassign' && $perm{'mgr'} ) {
- $request->print(&csvuploadassign($request));
+ &startpage($request,$symb,[{href=>'', text=>'Upload Scores'}],1,1);
+ $request->print(&csvuploadassign($request,$symb));
} elsif ($command eq 'scantron_selectphase' && $perm{'mgr'}) {
- $request->print(&scantron_selectphase($request));
+ &startpage($request,$symb,[{href=>'', text=>'Grade/Manage/Review Bubblesheets'}],1,1);
+ $request->print(&scantron_selectphase($request,undef,$symb));
} elsif ($command eq 'scantron_warning' && $perm{'mgr'}) {
- $request->print(&scantron_do_warning($request));
+ &startpage($request,$symb,[{href=>'', text=>'Grade/Manage/Review Bubblesheets'}],1,1);
+ $request->print(&scantron_do_warning($request,$symb));
} elsif ($command eq 'scantron_validate' && $perm{'mgr'}) {
- $request->print(&scantron_validate_file($request));
+ &startpage($request,$symb,[{href=>'', text=>'Grade/Manage/Review Bubblesheets'}],1,1);
+ $request->print(&scantron_validate_file($request,$symb));
} elsif ($command eq 'scantron_process' && $perm{'mgr'}) {
- $request->print(&scantron_process_students($request));
+ &startpage($request,$symb,[{href=>'', text=>'Grade/Manage/Review Bubblesheets'}],1,1);
+ $request->print(&scantron_process_students($request,$symb));
} elsif ($command eq 'scantronupload' &&
(&Apache::lonnet::allowed('usc',$env{'request.role.domain'})||
&Apache::lonnet::allowed('usc',$env{'request.course.id'}))) {
- $request->print(&scantron_upload_scantron_data($request));
+ &startpage($request,$symb,[{href=>'', text=>'Grade/Manage/Review Bubblesheets'}],1,1);
+ $request->print(&scantron_upload_scantron_data($request,$symb));
} elsif ($command eq 'scantronupload_save' &&
(&Apache::lonnet::allowed('usc',$env{'request.role.domain'})||
&Apache::lonnet::allowed('usc',$env{'request.course.id'}))) {
- $request->print(&scantron_upload_scantron_data_save($request));
+ &startpage($request,$symb,[{href=>'', text=>'Grade/Manage/Review Bubblesheets'}],1,1);
+ $request->print(&scantron_upload_scantron_data_save($request,$symb));
} elsif ($command eq 'scantron_download' &&
&Apache::lonnet::allowed('usc',$env{'request.course.id'})) {
- $request->print(&scantron_download_scantron_data($request));
+ &startpage($request,$symb,[{href=>'', text=>'Grade/Manage/Review Bubblesheets'}],1,1);
+ $request->print(&scantron_download_scantron_data($request,$symb));
} elsif ($command eq 'checksubmissions' && $perm{'vgr'}) {
- $request->print(&checkscantron_results($request));
+ &startpage($request,$symb,[{href=>'', text=>'Grade/Manage/Review Bubblesheets'}],1,1);
+ $request->print(&checkscantron_results($request,$symb));
+ } elsif ($command eq 'downloadfilesselect' && $perm{'vgr'}) {
+ &startpage($request,$symb,[{href=>'', text=>'Select which submissions to download'}]);
+ $request->print(&submit_options_download($request,$symb));
+ } elsif ($command eq 'downloadfileslink' && $perm{'vgr'}) {
+ &startpage($request,$symb,
+ [{href=>&href_symb_cmd($symb,'downloadfilesselect'), text=>'Select which submissions to download'},
+ {href=>'', text=>'Download submissions'}]);
+ &submit_download_link($request,$symb);
} elsif ($command) {
+ &startpage($request,$symb,[{href=>'', text=>'Access denied'}]);
$request->print(''.&mt('Access Denied ([_1])',$command).'
');
}
}
if ($ssi_error) {
&ssi_print_error($request);
}
- $request->print(&Apache::loncommon::end_page());
+ if ($env{'form.inhibitmenu'}) {
+ $request->print(&Apache::loncommon::end_page());
+ } else {
+ &Apache::lonquickgrades::endGradeScreen($request);
+ }
&reset_caches();
return OK;
}
@@ -9729,7 +10366,7 @@ described at http://www.lon-capa.org.
=head1 OVERVIEW
Do an ssi with retries:
-While I'd love to factor out this with the vesrion in lonprintout,
+While I'd love to factor out this with the version in lonprintout,
that would either require a data coupling between modules, which I refuse to perpetuate (there's quite enough of that already), or would require the invention of another infrastructure
I'm not quite ready to invent (e.g. an ssi_with_retry object).
@@ -9740,11 +10377,11 @@ At least the logic that drives this has
ssi_with_retries - Does the server side include of a resource.
if the ssi call returns an error we'll retry it up to
the number of times requested by the caller.
- If we still have a proble, no text is appended to the
+ If we still have a problem, no text is appended to the
output and we set some global variables.
to indicate to the caller an SSI error occurred.
All of this is supposed to deal with the issues described
- in LonCAPA BZ 5631 see:
+ in LON-CAPA BZ 5631 see:
http://bugs.lon-capa.org/show_bug.cgi?id=5631
by informing the user that this happened.
@@ -9776,6 +10413,75 @@ ssi_with_retries()
=over
+=head1 Routines to display previous version of a Task for a specific student
+
+Tasks are graded pass/fail. Students who have yet to pass a particular Task
+can receive another opportunity. Access to tasks is slot-based. If a slot
+requires a proctor to check-in the student, a new version of the Task will
+be created when the student is checked in to the new opportunity.
+
+If a particular student has tried two or more versions of a particular task,
+the submission screen provides a user with vgr privileges (e.g., a Course
+Coordinator) the ability to display a previous version worked on by the
+student. By default, the current version is displayed. If a previous version
+has been selected for display, submission data are only shown that pertain
+to that particular version, and the interface to submit grades is not shown.
+
+=over 4
+
+=item show_previous_task_version()
+
+Displays a specified version of a student's Task, as the student sees it.
+
+Inputs: 2
+ request - request object
+ symb - unique symb for current instance of resource
+
+Output: None.
+
+Side Effects: calls &show_problem() to print version of Task, with
+ version contained in form item: $env{'form.previousversion'}
+
+=item choose_task_version_form()
+
+Displays a web form used to select which version of a student's view of a
+Task should be displayed. Either launches a pop-up window, or replaces
+content in existing pop-up, or replaces page in main window.
+
+Inputs: 4
+ symb - unique symb for current instance of resource
+ uname - username of student
+ udom - domain of student
+ nomenu - 1 if display is in a pop-up window, and hence no menu
+ breadcrumbs etc., are displayed
+
+Output: 4
+ current - student's current version
+ displayed - student's version being displayed
+ result - scalar containing HTML for web form used to switch to
+ a different version (or a link to close window, if pop-up).
+ js - javascript for processing selection in versions web form
+
+Side Effects: None.
+
+=item previous_display_javascript()
+
+Inputs: 2
+ nomenu - 1 if display is in a pop-up window, and hence no menu
+ breadcrumbs etc., are displayed.
+ current - student's current version number.
+
+Output: 1
+ js - javascript for processing selection in versions web form.
+
+Side Effects: None.
+
+=back
+
+=head1 Routines to process bubblesheet data.
+
+=over 4
+
=item scantron_get_correction() :
Builds the interface screen to interact with the operator to fix a
@@ -9802,6 +10508,17 @@ ssi_with_retries()
- missingbubble - array ref of the bubble lines that have missing
bubble errors
+ $randomorder - True if exam folder has randomorder set
+ $randompick - True if exam folder has randompick set
+ $respnumlookup - Reference to HASH mapping question numbers in bubble lines
+ for current line to question number used for same question
+ in "Master Seqence" (as seen by Course Coordinator).
+ $startline - Reference to hash where key is question number (0 is first)
+ and value is number of first bubble line for current student
+ or code-based randompick and/or randomorder.
+
+
+
=item scantron_get_maxbubble() :
Arguments:
@@ -9822,7 +10539,7 @@ ssi_with_retries()
$env{'form.scantron.bubble_lines.n'},
$env{'form.scantron.first_bubble_line.n'} and
$env{"form.scantron.sub_bubblelines.n"}
- which are the total number of bubble, lines, the number of bubble
+ which are the total number of bubble lines, the number of bubble
lines for response n and number of the first bubble line for response n,
and a comma separated list of numbers of bubble lines for sub-questions
(for optionresponse, matchresponse, and rankresponse items), for response n.
@@ -9881,7 +10598,9 @@ ssi_with_retries()
=item navmap_errormsg() :
Returns HTML mark-up inside a
with a link to re-initialize the course.
- Should be called whenever the request to instantiate a navmap object fails.
+ Should be called whenever the request to instantiate a navmap object fails.
+
+=back
=back