--- loncom/homework/grades.pm 2011/11/29 17:00:19 1.664
+++ loncom/homework/grades.pm 2012/05/02 14:00:28 1.672
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# The LON-CAPA Grading handler
#
-# $Id: grades.pm,v 1.664 2011/11/29 17:00:19 raeburn Exp $
+# $Id: grades.pm,v 1.672 2012/05/02 14:00:28 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -1524,17 +1524,15 @@ INNERJS
function savedMsgHeader(Nmsg,usrctr,fullname) {
var height = 70*Nmsg+250;
- var scrollbar = "no";
if (height > 600) {
height = 600;
- scrollbar = "yes";
}
var xpos = (screen.width-600)/2;
xpos = (xpos < 0) ? '0' : xpos;
var ypos = (screen.height-height)/2-30;
ypos = (ypos < 0) ? '0' : ypos;
- pWin = window.open('', 'MessageCenter', 'resizable=yes,toolbar=no,location=no,scrollbars='+scrollbar+',screenx='+xpos+',screeny='+ypos+',width=700,height='+height);
+ pWin = window.open('', 'MessageCenter', 'resizable=yes,toolbar=no,location=no,scrollbars=yes,screenx='+xpos+',screeny='+ypos+',width=700,height='+height);
pWin.focus();
pDoc = pWin.document;
pDoc.$docopen;
@@ -1829,14 +1827,27 @@ sub show_problem {
$companswer=~s|||g;
$companswer=~s|name="submit"|name="would_have_been_submit"|g;
}
+ my $renderheading = &mt('View of the problem');
+ my $answerheading = &mt('Correct answer');
+ if (($uname ne $env{'user.name'}) || ($udom ne $env{'user.domain'})) {
+ my $stu_fullname = $env{'form.fullname'};
+ if ($stu_fullname eq '') {
+ $stu_fullname = &Apache::loncommon::plainname($uname,$udom,'lastname');
+ }
+ my $forwhom = &nameUserString(undef,$stu_fullname,$uname,$udom);
+ if ($forwhom ne '') {
+ $renderheading = &mt('View of the problem for[_1]',$forwhom);
+ $answerheading = &mt('Correct answer for[_1]',$forwhom);
+ }
+ }
$rendered=
'
'
- .'
'.&mt('View of the problem').'
'
+ .'
'.$renderheading.'
'
.$rendered
.'
';
$companswer=
'
'
- .'
'.&mt('Correct answer').'
'
+ .'
'.$answerheading.'
'
.$companswer
.'
';
my $result;
@@ -2508,6 +2519,183 @@ 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('Unable to view previous version for requested student.('.
+ $uname.':'.$udom.' in section '.$usec.' in course id '.
+ $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".
+ '
';
+ }
+ return ($current,$displayed,$result,$js);
+}
+
+sub previous_display_javascript {
+ my ($nomenu,$current) = @_;
+ my $js = <<"JSONE";
+
+ENDJS
+
+}
+
#--- Called from submission routine
sub processHandGrade {
my ($request,$symb) = @_;
@@ -4540,6 +4728,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();
@@ -4560,7 +4749,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().
@@ -4568,6 +4759,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}) {
@@ -4587,7 +4781,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).')'
@@ -5412,6 +5606,7 @@ sub scantron_selectphase {
LastNameLength - number of columns that the last name spans
BubblesPerRow - number of bubbles available in each row used to
bubble an answer. (If not specified, 10 assumed).
+
=cut
sub get_scantron_config {
@@ -6909,7 +7104,7 @@ sub scantron_get_correction {
.&mt('The ID on the form is [_1]',
"$$scan_record{'scantron.ID'}")
.' '
- .&mt('The name on the paper is [_2], [_3]',
+ .&mt('The name on the paper is [_1], [_2]',
$$scan_record{'scantron.LastName'},
$$scan_record{'scantron.FirstName'})
.'';
@@ -7518,7 +7713,8 @@ sub scantron_get_maxbubble {
my $response_number = 0;
my $bubble_line = 0;
foreach my $resource (@resources) {
- my ($analysis,$parts) = &scantron_partids_tograde($resource,$cid,$uname,$udom,undef,$bubbles_per_row);
+ my ($analysis,$parts) = &scantron_partids_tograde($resource,$cid,$uname,
+ $udom,undef,$bubbles_per_row);
if ((ref($analysis) eq 'HASH') && (ref($parts) eq 'ARRAY')) {
foreach my $part_id (@{$parts}) {
my $lines;
@@ -7723,7 +7919,8 @@ sub scantron_process_students {
}
my ($analysis,$parts) =
&scantron_partids_tograde($resource,$env{'request.course.id'},
- $env{'user.name'},$env{'user.domain'},1,$bubbles_per_row);
+ $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') {
@@ -7750,11 +7947,8 @@ SCANTRONFORM
my $lock=&Apache::lonnet::set_lock(&mt('Grading bubblesheet exam'));
my $count=&get_todo_count($scanlines,$scan_data);
- my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin($r,'Bubblesheet Status',
- 'Bubblesheet Progress',$count,
- 'inline',undef,'scantronupload');
- &Apache::lonhtmlcommon::Update_PrgWin($r,\%prog_state,
- 'Processing first student');
+ my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin($r,$count);
+ &Apache::lonhtmlcommon::Update_PrgWin($r,\%prog_state,'Processing first student');
$r->print(' ');
my $start=&Time::HiRes::time();
my $i=-1;
@@ -7786,8 +7980,7 @@ 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 $scan_record=&scantron_parse_scanline($line,$i,\%scantron_config,
@@ -7817,7 +8010,8 @@ SCANTRONFORM
if ((exists($grader_randomlists_by_symb{$ressymb})) ||
(ref($grader_partids_by_symb{$ressymb}) ne 'ARRAY')) {
my ($analysis,$parts) =
- &scantron_partids_tograde($resource,$env{'request.course.id'},$uname,$udom,undef,$bubbles_per_row);
+ &scantron_partids_tograde($resource,$env{'request.course.id'},
+ $uname,$udom,undef,$bubbles_per_row);
$partids_by_symb{$ressymb} = $parts;
} else {
$partids_by_symb{$ressymb} = $grader_partids_by_symb{$ressymb};
@@ -7946,7 +8140,8 @@ sub graders_resources_pass {
my $ressymb = $resource->symb();
my ($analysis,$parts) =
&scantron_partids_tograde($resource,$env{'request.course.id'},
- $env{'user.name'},$env{'user.domain'},1,$bubbles_per_row);
+ $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') {
@@ -8278,9 +8473,7 @@ sub checkscantron_results {
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 %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.
@@ -8289,8 +8482,7 @@ sub checkscantron_results {
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;
@@ -8300,8 +8492,7 @@ 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=
@@ -8333,7 +8524,9 @@ sub checkscantron_results {
if ((exists($grader_randomlists_by_symb{$ressymb})) ||
(ref($grader_partids_by_symb{$ressymb}) ne 'ARRAY')) {
(my $analysis,$parts) =
- &scantron_partids_tograde($resource,$env{'request.course.id'},$username,$domain,undef,$bubbles_per_row);
+ &scantron_partids_tograde($resource,$env{'request.course.id'},
+ $username,$domain,undef,
+ $bubbles_per_row);
} else {
$parts = $grader_partids_by_symb{$ressymb};
}
@@ -8553,7 +8746,7 @@ sub letter_to_digits {
sub href_symb_cmd {
my ($symb,$cmd)=@_;
- return '/adm/grades?symb='.&HTML::Entities::encode(&Apache::lonenc::check_encrypt($symb),'<>&"').'&command='.$cmd;
+ return '/adm/grades?symb='.&HTML::Entities::encode(&Apache::lonenc::check_encrypt($symb),'<>&"').'&command='.$cmd;
}
sub grading_menu {
@@ -8913,7 +9106,8 @@ sub process_clicker {
my $pincorrect=&mt("Percentage points for incorrect solution");
my $selectform=&Apache::loncommon::select_form($env{'form.upfiletype'},'upfiletype',
{'iclicker' => 'i>clicker',
- 'interwrite' => 'interwrite PRS'});
+ 'interwrite' => 'interwrite PRS',
+ 'turning' => 'Turning Technologies'});
$symb = &Apache::lonenc::check_encrypt($symb);
$result.= &Apache::lonhtmlcommon::scripttag(<'.&mt('Found [_1] question(s)',$number).' '.
''.
&mt('Awarding [_1] percent for correct and [_2] percent for incorrect responses',
@@ -9223,6 +9420,32 @@ 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,$symb)=@_;
if (!$symb) {return '';}
@@ -9360,13 +9583,17 @@ sub navmap_errormsg {
}
sub startpage {
- my ($r,$symb,$crumbs,$onlyfolderflag,$nodisplayflag) = @_;
- unshift(@$crumbs,{href=>&href_symb_cmd($symb,'gradingmenu'),text=>"Grading"});
- $r->print(&Apache::loncommon::start_page('Grading',undef,
- {'bread_crumbs' => $crumbs}));
- &Apache::lonquickgrades::startGradeScreen($r,($env{'form.symb'}?'probgrading':'grading'));
+ 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));
+ $r->print(&Apache::lonhtmlcommon::resource_info_box($symb,$onlyfolderflag,$stuvcurrent,$stuvdisp));
}
}
@@ -9429,8 +9656,29 @@ sub handler {
&select_problem($request);
} else {
if ($command eq 'submission' && $perm{'vgr'}) {
- &startpage($request,$symb,[{href=>"", text=>"Student Submissions"}]);
+ 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'}) {
&startpage($request,$symb,[{href=>&href_symb_cmd($symb,'all_for_one'),text=>'Grade page/folder for one student'},
{href=>'',text=>'Select student'}],1,1);
@@ -9568,8 +9816,11 @@ sub handler {
if ($ssi_error) {
&ssi_print_error($request);
}
- &Apache::lonquickgrades::endGradeScreen($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;
}
@@ -9640,6 +9891,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
@@ -9745,7 +10065,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