# The LearningOnline Network with CAPA
# input definitons
#
# $Id: inputtags.pm,v 1.286 2011/04/29 01:41:12 www Exp $
#
# Copyright Michigan State University Board of Trustees
#
# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
#
# LON-CAPA is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# LON-CAPA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with LON-CAPA; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# /home/httpd/html/adm/gpl.txt
#
# http://www.lon-capa.org/
=pod
=head1 NAME
Apache::inputtags
=head1 SYNOPSIS
This is part of the LearningOnline Network with CAPA project
described at http://www.lon-capa.org.
=head1 NOTABLE SUBROUTINES
=over
=item
=back
=cut
package Apache::inputtags;
use HTML::Entities();
use strict;
use Apache::loncommon;
use Apache::lonhtmlcommon;
use Apache::lonlocal;
use Apache::lonnet;
use LONCAPA;
BEGIN {
&Apache::lonxml::register('Apache::inputtags',('hiddensubmission','hiddenline','textfield','textline'));
}
=pod
=item initialize_inputtags()
Initializes a set of global variables used during the parse of the problem.
@Apache::inputtags::input - List of current input ids.
@Apache::inputtags::inputlist - List of all input ids seen this problem.
@Apache::inputtags::response - List of all current resopnse ids.
@Apache::inputtags::responselist - List of all response ids seen this
problem.
@Apache::inputtags::hint - List of all hint ids.
@Apache::inputtags::hintlist - List of all hint ids seen this problem.
@Apache::inputtags::previous - List describing if specific responseds
have been used
@Apache::inputtags::previous_version - Submission responses were used in.
$Apache::inputtags::part - Current part id (valid only in
<problem>)
0 if not in a part.
@Apache::inputtags::partlist - List of part ids seen in the current
<problem>
@Apache::inputtags::status - List of problem statuses. First
element is the status of the <problem>
the remainder are for individual <part>s.
%Apache::inputtags::params - Hash of defined parameters for the
current response.
@Apache::inputtags::import - List of all ids for <import> thes get
join()ed and prepended.
@Apache::inputtags::importlist - List of all import ids seen.
$Apache::inputtags::response_with_no_part
- Flag set true if we have seen a response
that is not inside a <part>
%Apache::inputtags::answertxt - <*response> tags store correct
answer strings for display by <textline/>
in this hash.
%Apache::inputtags::submission_display
- <*response> tags store improved display
of submission strings for display by part
end.
=cut
sub initialize_inputtags {
@Apache::inputtags::input=();
@Apache::inputtags::inputlist=();
@Apache::inputtags::response=();
@Apache::inputtags::responselist=();
@Apache::inputtags::hint=();
@Apache::inputtags::hintlist=();
@Apache::inputtags::previous=();
@Apache::inputtags::previous_version=();
$Apache::inputtags::part='';
@Apache::inputtags::partlist=();
@Apache::inputtags::status=();
%Apache::inputtags::params=();
@Apache::inputtags::import=();
@Apache::inputtags::importlist=();
$Apache::inputtags::response_with_no_part=0;
%Apache::inputtags::answertxt=();
%Apache::inputtags::submission_display=();
}
sub check_for_duplicate_ids {
my %check;
foreach my $id (@Apache::inputtags::partlist,
@Apache::inputtags::responselist,
@Apache::inputtags::hintlist,
@Apache::inputtags::importlist) {
$check{$id}++;
}
my @duplicates;
foreach my $id (sort(keys(%check))) {
if ($check{$id} > 1) {
push(@duplicates,$id);
}
}
if (@duplicates) {
&Apache::lonxml::error("Duplicated ids found, problem will operate incorrectly. Duplicated ids seen: ",join(', ',@duplicates));
}
}
sub start_input {
my ($parstack,$safeeval)=@_;
my $id = &Apache::lonxml::get_id($parstack,$safeeval);
push (@Apache::inputtags::input,$id);
push (@Apache::inputtags::inputlist,$id);
return $id;
}
sub end_input {
pop @Apache::inputtags::input;
return '';
}
sub addchars {
my ($fieldid,$addchars)=@_;
my $output='';
foreach (split(/\,/,$addchars)) {
$output.='<a href="javascript:void(document.forms.lonhomework.'.
$fieldid.'.value+=\''.$_.'\')">'.$_.'</a> ';
}
return $output;
}
sub start_textfield {
my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
my $result = "";
my $id = &start_input($parstack,$safeeval);
my $resid=$Apache::inputtags::response[-1];
if ($target eq 'web') {
$Apache::lonxml::evaluate--;
my $partid=$Apache::inputtags::part;
my ($oldresponse,$newvariation);
if ((($Apache::lonhomework::history{"resource.$partid.type"} eq 'randomizetry') ||
($Apache::lonhomework::type eq 'randomizetry')) &&
($Apache::inputtags::status[-1] eq 'CAN_ANSWER')) {
if ($env{'form.'.$partid.'.rndseed'} ne
$Apache::lonhomework::history{"resource.$partid.rndseed"}) {
$newvariation = 1;
}
}
unless ($newvariation) {
$oldresponse = &HTML::Entities::encode($Apache::lonhomework::history{"resource.$partid.$resid.submission"},'<>&"');
}
if ($Apache::inputtags::status[-1] eq 'CAN_ANSWER') {
my $cols = &Apache::lonxml::get_param('cols',$parstack,$safeeval);
if ( $cols eq '') { $cols = 80; }
my $rows = &Apache::lonxml::get_param('rows',$parstack,$safeeval);
if ( $rows eq '') { $rows = 16; }
my $addchars=&Apache::lonxml::get_param('addchars',$parstack,$safeeval);
$result='';
if ($addchars) {
$result.=&addchars('HWVAL_'.$resid,$addchars);
}
my $textareaclass = 'class="LC_richDetectHtml"';
$result.= '<textarea wrap="hard" name="HWVAL_'.$resid.'" id="HWVAL_'.$resid.'" '.
'rows="'.$rows.'" cols="'.$cols.'" '.$textareaclass.'>'.
$oldresponse;
if ($oldresponse ne '') {
#get rid of any startup text if the user has already responded
&Apache::lonxml::get_all_text("/textfield",$parser,$style);
}
} else {
#show past answer in the essayresponse case
if ($oldresponse =~ /\S/
&& &Apache::londefdef::is_inside_of($tagstack,
'essayresponse') ) {
$result='<table class="LC_pastsubmission"><tr><td>'.
$oldresponse.'</td></tr></table>';
}
#get rid of any startup text
&Apache::lonxml::get_all_text("/textfield",$parser,$style);
}
} elsif ($target eq 'grade') {
my $seedtext=&Apache::lonxml::get_all_text("/textfield",$parser,
$style);
if ($seedtext eq $env{'form.HWVAL_'.$resid}) {
# if the seed text is still there it wasn't a real submission
$env{'form.HWVAL_'.$resid}='';
}
} elsif ($target eq 'edit') {
$result.=&Apache::edit::tag_start($target,$token);
$result.=&Apache::edit::text_arg('Rows:','rows',$token,4);
$result.=&Apache::edit::text_arg('Columns:','cols',$token,4);
$result.=&Apache::edit::text_arg
('Click-On Texts (comma sep):','addchars',$token,10);
my $bodytext=&Apache::lonxml::get_all_text("/textfield",$parser,
$style);
$result.=&Apache::edit::editfield($token->[1],$bodytext,'Text you want to appear by default:',80,2);
} elsif ($target eq 'modified') {
my $constructtag=&Apache::edit::get_new_args($token,$parstack,
$safeeval,'rows','cols',
'addchars');
if ($constructtag) {
$result = &Apache::edit::rebuild_tag($token);
} else {
$result=$token->[4];
}
$result.=&Apache::edit::modifiedfield("/textfield",$parser);
} elsif ($target eq 'tex') {
my $number_of_lines = &Apache::lonxml::get_param('rows',$parstack,$safeeval);
my $width_of_box = &Apache::lonxml::get_param('cols',$parstack,$safeeval);
if ($$tagstack[-2] eq 'essayresponse' and $Apache::lonhomework::type eq 'exam') {
$result = '\fbox{\fbox{\parbox{\textwidth-5mm}{';
for (my $i=0;$i<int $number_of_lines*2;$i++) {$result.='\strut \\\\ ';}
$result.='\strut \\\\\strut \\\\\strut \\\\\strut \\\\}}}';
} else {
my $TeXwidth=$width_of_box/80;
$result = '\vskip 1 mm \fbox{\fbox{\parbox{'.$TeXwidth.'\textwidth-5mm}{';
for (my $i=0;$i<int $number_of_lines*2;$i++) {$result.='\strut \\\\ ';}
$result.='}}}\vskip 2 mm ';
}
}
return $result;
}
sub end_textfield {
my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
my $result;
if ($target eq 'web') {
$Apache::lonxml::evaluate++;
if ($Apache::inputtags::status[-1] eq 'CAN_ANSWER') {
return "</textarea>";
}
} elsif ($target eq 'edit') {
$result=&Apache::edit::end_table();
}
&end_input;
return $result;
}
sub exam_score_line {
my ($target) = @_;
my $result;
if ($target eq 'tex') {
my $repetition = &Apache::response::repetition();
$result.='\begin{enumerate}';
if ($env{'request.state'} eq "construct" ) {$result.='\item[\strut]';}
foreach my $i (0..$repetition-1) {
$result.='\item[\textbf{'.
($Apache::lonxml::counter+$i).
'}.]\textit{Leave blank on scoring form}\vskip 0 mm';
}
$result.= '\end{enumerate}';
}
return $result;
}
sub exam_box {
my ($target) = @_;
my $result;
if ($target eq 'tex') {
$result .= '\fbox{\fbox{\parbox{\textwidth-5mm}{\strut\\\\\strut\\\\\strut\\\\\strut\\\\}}}';
$result .= &exam_score_line($target);
} elsif ($target eq 'web') {
my $id=$Apache::inputtags::response[-1];
$result.= '<br /><br />
<textarea name="HWVAL_'.$id.'" rows="4" cols="50">
</textarea> <br /><br />';
}
return $result;
}
sub needs_exam_box {
my ($tagstack) = @_;
my @tags = ('formularesponse',
'stringresponse',
'reactionresponse',
'organicresponse',
);
foreach my $tag (@tags) {
if (grep(/\Q$tag\E/,@$tagstack)) {
return 1;
}
}
return 0;
}
sub start_textline {
my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
my $result = "";
my $input_id = &start_input($parstack,$safeeval);
if ($target eq 'web') {
$Apache::lonxml::evaluate--;
my $partid=$Apache::inputtags::part;
my $id=$Apache::inputtags::response[-1];
if (!&Apache::response::show_answer()) {
my $size = &Apache::lonxml::get_param('size',$parstack,$safeeval);
my $maxlength;
if ($size eq '') { $size=20; } else {
if ($size < 20) {
$maxlength = ' maxlength="'.$size.'"';
}
}
my ($oldresponse,$newvariation);
if ((($Apache::lonhomework::history{"resource.$partid.type"} eq 'randomizetry') ||
($Apache::lonhomework::type eq 'randomizetry')) &&
($Apache::inputtags::status[-1] eq 'CAN_ANSWER')) {
if ($env{'form.'.$partid.'.rndseed'} ne
$Apache::lonhomework::history{"resource.$partid.rndseed"}) {
$newvariation = 1;
}
}
unless ($newvariation) {
$oldresponse = $Apache::lonhomework::history{"resource.$partid.$id.submission"};
&Apache::lonxml::debug("oldresponse $oldresponse is ".ref($oldresponse));
if (ref($oldresponse) eq 'ARRAY') {
$oldresponse = $oldresponse->[$#Apache::inputtags::inputlist];
}
$oldresponse = &HTML::Entities::encode($oldresponse,'<>&"');
$oldresponse =~ s/^\s+//;
$oldresponse =~ s/\s+$//;
$oldresponse =~ s/\s+/ /g;
}
if ($Apache::lonhomework::type ne 'exam') {
my $addchars=&Apache::lonxml::get_param('addchars',$parstack,$safeeval);
$result='';
if ($addchars) {
$result.=&addchars('HWVAL_'.$id,$addchars);
}
my $readonly=&Apache::lonxml::get_param('readonly',$parstack,
$safeeval);
if (lc($readonly) eq 'yes'
|| $Apache::inputtags::status[-1] eq 'CANNOT_ANSWER') {
$readonly=' readonly="readonly" ';
} else {
$readonly='';
}
my $name = 'HWVAL_'.$id;
if ($Apache::inputtags::status[-1] eq 'CANNOT_ANSWER') {
$name = "none";
}
$result.= '<input onkeydown="javascript:setSubmittedPart(\''.$partid.'\');" type="text" '.$readonly.' name="'.$name.'" value="'.
$oldresponse.'" size="'.$size.'"'.$maxlength.' />';
}
if ($Apache::lonhomework::type eq 'exam'
&& &needs_exam_box($tagstack)) {
$result.=&exam_box($target);
}
} else {
#right or wrong don't show what was last typed in.
my $count = scalar(@Apache::inputtags::inputlist)-1;
$result='<b>'.$Apache::inputtags::answertxt{$id}[$count].'</b>';
#$result='';
}
} elsif ($target eq 'edit') {
$result=&Apache::edit::tag_start($target,$token);
$result.=&Apache::edit::text_arg('Size:','size',$token,'5').
&Apache::edit::text_arg('Click-On Texts (comma sep):',
'addchars',$token,10);
$result.=&Apache::edit::select_arg('Readonly:','readonly',
['no','yes'],$token);
$result.=&Apache::edit::end_row();
$result.=&Apache::edit::end_table();
} elsif ($target eq 'modified') {
my $constructtag=&Apache::edit::get_new_args($token,$parstack,
$safeeval,'size',
'addchars','readonly');
if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); }
} elsif ($target eq 'tex'
&& $Apache::lonhomework::type ne 'exam') {
my $size = &Apache::lonxml::get_param('size',$parstack,$safeeval);
if ($size != 0) {$size=$size*2; $size.=' mm';} else {$size='40 mm';}
if ($env{'form.pdfFormFields'} eq 'yes'
&& $Apache::inputtags::status[-1] eq 'CAN_ANSWER') {
my $fieldname = $env{'request.symb'}.
'&part_'. $Apache::inputtags::part.
'&textresponse'.
'&HWVAL_' . $Apache::inputtags::response['-1'];
$result='\textField{'.$fieldname.'}{'.$size.'}{12 bp}';
} else {
$result='\framebox['.$size.'][s]{\tiny\strut}';
}
} elsif ($target eq 'tex'
&& $Apache::lonhomework::type eq 'exam'
&& &needs_exam_box($tagstack)) {
$result.=&exam_box($target);
}
return $result;
}
sub end_textline {
my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
if ($target eq 'web') { $Apache::lonxml::evaluate++; }
elsif ($target eq 'edit') { return ('','no'); }
&end_input();
return "";
}
sub start_hiddenline {
my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
my $result = "";
my $input_id = &start_input($parstack,$safeeval);
if ($target eq 'web') {
$Apache::lonxml::evaluate--;
if ($Apache::inputtags::status[-1] eq 'CAN_ANSWER') {
my $partid=$Apache::inputtags::part;
my $id=$Apache::inputtags::response[-1];
my $oldresponse = $Apache::lonhomework::history{"resource.$partid.$id.submission"};
if (ref($oldresponse) eq 'ARRAY') {
$oldresponse = $oldresponse->[$#Apache::inputtags::inputlist];
}
$oldresponse = &HTML::Entities::encode($oldresponse,'<>&"');
if ($Apache::lonhomework::type ne 'exam') {
$result= '<input type="hidden" name="HWVAL_'.$id.'" value="'.
$oldresponse.'" />';
}
}
} elsif ($target eq 'edit') {
$result=&Apache::edit::tag_start($target,$token);
$result.=&Apache::edit::end_table;
}
if ( ($target eq 'web' || $target eq 'tex')
&& $Apache::lonhomework::type eq 'exam'
&& &needs_exam_box($tagstack)) {
$result.=&exam_box($target);
}
return $result;
}
sub end_hiddenline {
my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
if ($target eq 'web') { $Apache::lonxml::evaluate++; }
elsif ($target eq 'edit') { return ('','no'); }
&end_input();
return "";
}
sub start_hiddensubmission {
my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
my $result = "";
my $input_id = &start_input($parstack,$safeeval);
if ($target eq 'web') {
$Apache::lonxml::evaluate--;
if ($Apache::inputtags::status[-1] eq 'CAN_ANSWER') {
my $partid=$Apache::inputtags::part;
my $id=$Apache::inputtags::response[-1];
if ($Apache::lonhomework::type ne 'exam') {
my $value = &Apache::lonxml::get_param('value',$parstack,$safeeval);
$value = &HTML::Entities::encode($value,'<>&"');
$result= '<input type="hidden" name="HWVAL_'.$id.'" value="'.$value.'" />';
}
}
} elsif ($target eq 'edit') {
$result=&Apache::edit::tag_start($target,$token);
$result.=&Apache::edit::text_arg('Value:','value',$token,'15');
$result.=&Apache::edit::end_row();
$result.=&Apache::edit::end_table();
} elsif ($target eq 'modified') {
my $constructtag=&Apache::edit::get_new_args($token,$parstack,
$safeeval,'value');
if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); }
}
if ( ($target eq 'web' || $target eq 'tex')
&& $Apache::lonhomework::type eq 'exam'
&& &needs_exam_box($tagstack)) {
$result.=&exam_box($target);
}
return $result;
}
sub end_hiddensubmission {
my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
if ($target eq 'web') { $Apache::lonxml::evaluate++; }
elsif ($target eq 'edit') { return ('','no'); }
&end_input();
return "";
}
=pod
=item file_selector()
$part -> partid
$id -> responseid
$uploadefiletypes -> comma seperated list of extensions allowed or * for any
$which -> 'uploadonly' -> only newly uploaded files
'portfolioonly' -> only allow files from portfolio
'both' -> allow files from either location
$extratext -> additional text to go between the link and the input box
$maxfilesize -> maximum cumulative filesize for submitted files (in MB).
returns a table row <tr>
=cut
sub file_selector {
my ($part,$id,$uploadedfiletypes,$which,$extratext,$maxfilesize)=@_;
if (!$uploadedfiletypes) { return ''; }
my $jspart=$part;
$jspart=~s/\./_/g;
my $result;
my $current_files_display = ¤t_file_submissions($part,$id);
my $addfiles;
if ($current_files_display) {
$result .= &Apache::lonhtmlcommon::row_title(&mt('Currently submitted files')).
$current_files_display.
&Apache::lonhtmlcommon::row_closure();
$addfiles = &mt('Submit other file(s)');
} else {
$addfiles = &mt('Choose file(s) to submit');
}
$result .= &Apache::lonhtmlcommon::row_title($addfiles);
my $constraints;
if ($uploadedfiletypes ne '*') {
$constraints =
&mt('Allowed filetypes: [_1]','<b>'.$uploadedfiletypes.'</b>').'<br />';
}
if ($maxfilesize) {
$constraints .= &mt('Combined size of all files not to exceed: [_1] MB[_2].',
'<b>'.$maxfilesize.'</b>').'<br />';
}
if ($constraints) {
$result .= $constraints.'<br />';
}
if ($which eq 'uploadonly' || $which eq 'both') {
$result.=&mt('Submit a file: (only one file per submission)').
' <br /><input type="file" size="50" name="HWFILE'.
$jspart.'_'.$id.'" /><br />';
}
if ( $which eq 'both') {
$result.='<br />'.'<strong>'.&mt('OR:').'</strong><br />';
}
if ($which eq 'portfolioonly' || $which eq 'both') {
$result.=$extratext.'<a href='."'".'javascript:void(window.open("/adm/portfolio?mode=selectfile&fieldname='.$env{'form.request.prefix'}.'HWPORT'.$jspart.'_'.$id.'","cat","height=600,width=800,scrollbars=1,resizable=1,menubar=2,location=1"))'."'".'>'.
&mt('Select Portfolio Files: (one or more files per submission)').'</a><br />'.
'<input type="text" size="50" name="HWPORT'.$jspart.'_'.$id.'" value="" />'.
'<br />';
}
$result.=&Apache::lonhtmlcommon::row_closure(1);
return $result;
}
sub current_file_submissions {
my ($part,$id) = @_;
my $jspart=$part;
$jspart=~s/\./_/g;
my $uploadedfile=$Apache::lonhomework::history{"resource.$part.$id.uploadedfile"};
my $portfiles=$Apache::lonhomework::history{"resource.$part.$id.portfiles"};
return if (($uploadedfile eq '') && ($portfiles !~/[^\s]/));
my $header = &Apache::loncommon::start_data_table().
&Apache::loncommon::start_data_table_header_row();
if ($Apache::inputtags::status[-1] eq 'CAN_ANSWER') {
$header .= '<th>'.&mt('Delete?').'</th>';
}
$header .= '<th>'.&mt('File').'</th>'.
'<th>'.&mt('Size (MB)').'</th>'.
'<th>'.&mt('Last Modified').'</th>'.
&Apache::loncommon::end_data_table_header_row();
my (undef,$crsid,$udom,$uname)=&Apache::lonnet::whichuser();
my ($cdom,$cnum) = ($crsid =~ /^($LONCAPA::match_domain)_($LONCAPA::match_courseid)$/);
my ($result,$header_shown,%okfiles,%rows,%legacy,@bad_file_list);
if ($uploadedfile) {
my $url=$Apache::lonhomework::history{"resource.$part.$id.uploadedurl"};
my $link = &HTML::Entities::encode($url,'<>&"');
my ($path,$name) = ($url =~ m{^(/uploaded/\Q$udom\E/\Q$uname\E/essayresponse.*/)([^/]+)$});
my ($status,$hashref,$error) =
¤t_file_info($url,$link,$name,$path);
if ($status eq 'ok') {
push(@{$okfiles{$name}},$url);
$rows{$url} = $hashref;
$legacy{$url} = 1;
&Apache::lonxml::extlink($url);
&Apache::lonnet::allowuploaded('/adm/essayresponse',$url);
} else {
push(@bad_file_list,$error);
}
}
if ($portfiles =~ /[^\s]/) {
my $prefix = "/uploaded/$udom/$uname/portfolio";
foreach my $file (split(/\s*,\s*/,&unescape($portfiles))) {
my ($path,$name) = ($file =~ m{^(.*/)([^/]+)$});
my $url = $prefix.$path.$name;
my $uploadedfile = &HTML::Entities::encode($url,'<>&"');
my ($status,$hashref,$error) =
¤t_file_info($url,$uploadedfile,$name,$path);
if ($status eq 'ok') {
push(@{$okfiles{$name}},$url);
$rows{$url} = $hashref;
} else {
push(@bad_file_list,$error);
}
}
}
my $num = 0;
foreach my $name (sort(keys(%okfiles))) {
if (ref($okfiles{$name}) eq 'ARRAY') {
foreach my $url (@{$okfiles{$name}}) {
if (ref($rows{$url}) eq 'HASH') {
my $link = $rows{$url}{link};
my $portfile = $rows{$url}{path}.$rows{$url}{name};
$portfile = &HTML::Entities::encode($portfile,'<>&"');
if ($link) {
my $icon=&Apache::loncommon::icon($url);
unless ($header_shown) {
$result .= $header;
$header_shown = 1;
}
$result.=
&Apache::loncommon::start_data_table_row()."\n";
if ($Apache::inputtags::status[-1] eq 'CAN_ANSWER') {
$result .=
'<td valign="bottom"><input type="checkbox" name="HWFILE'.$jspart.'_'.$id.'_delete"'.
' value="'.$portfile.'" id="HWFILE'.$jspart.'_'.$id.'_'.$num.'_delete" /></td>'."\n";
$num ++;
}
my $showname = $rows{$url}{path}.$name;
if ($legacy{$url}) {
$showname = $name.' '.&mt('not in portfolio');
}
$result .=
'<td><a href="'.$link.'"><img src="'.$icon.
'" border="0" alt="" />'.$showname.'</a></td>'."\n".
'<td align="right" valign="bottom">'.$rows{$url}{size}.'</td>'."\n".
'<td align="right" valign="bottom">'.$rows{$url}{lastmodified}.'</td>'."\n".
&Apache::loncommon::end_data_table_row();
}
}
}
}
}
if ($header_shown) {
$result .= &Apache::loncommon::end_data_table().
'<br /><span class="LC_warning">'.
&mt('Exclude existing file(s) from grading by checking the "Delete?" checkbox(es) and clicking "Submit Answer"').'</span>';
}
if (@bad_file_list) {
my $bad_files = '<span class="LC_filename">'.
join('</span>, <span class="LC_filename">',@bad_file_list).
'</span>';
$result.='<p class="LC_error">'.
&mt("These file(s) don't exist: [_1]",$bad_files).
'</p>';
}
return $result;
}
sub current_file_info {
my ($url,$uploadedfile,$name,$path) = @_;
my ($status,$error,%info);
my @stat = &Apache::lonnet::stat_file($url);
if ((@stat) && ($stat[0] ne 'no_such_dir')) {
my ($lastmod,$size);
if ($stat[9] =~ /^\d+$/) {
$lastmod = &Apache::lonlocal::locallocaltime($stat[9]);
}
$size = $stat[7]/(1024*1024);
$size = sprintf("%.3f",$size);
%info = (
link => $uploadedfile,
name => $name,
path => $path,
size => $size,
lastmodified => $lastmod,
);
$status = 'ok';
} else {
&Apache::lonnet::logthis("bad file is $url");
my $icon=&Apache::loncommon::icon($url);
$error = '<a href="'.$url.'"><img src="'.$icon.
'" border="0" />'.$uploadedfile.'</a>';
}
return ($status,\%info,$error);
}
sub valid_award {
my ($award) =@_;
foreach my $possibleaward ('EXTRA_ANSWER','MISSING_ANSWER', 'ERROR',
'NO_RESPONSE',
'TOO_LONG', 'UNIT_INVALID_INSTRUCTOR',
'UNIT_INVALID_STUDENT', 'UNIT_IRRECONCIBLE',
'UNIT_FAIL', 'NO_UNIT',
'UNIT_NOTNEEDED', 'WANTED_NUMERIC',
'BAD_FORMULA', 'NOT_FUNCTION', 'WRONG_FORMAT',
'INTERNAL_ERROR', 'SIG_FAIL', 'INCORRECT',
'MISORDERED_RANK', 'INVALID_FILETYPE',
'EXCESS_FILESIZE', 'FILENAME_INUSE',
'DRAFT', 'SUBMITTED', 'SUBMITTED_CREDIT',
'ANONYMOUS', 'ANONYMOUS_CREDIT',
'ASSIGNED_SCORE', 'APPROX_ANS',
'EXACT_ANS','COMMA_FAIL') {
if ($award eq $possibleaward) { return 1; }
}
return 0;
}
{
my @awards = ('EXTRA_ANSWER', 'MISSING_ANSWER', 'ERROR', 'NO_RESPONSE',
'TOO_LONG',
'UNIT_INVALID_INSTRUCTOR', 'UNIT_INVALID_STUDENT',
'UNIT_IRRECONCIBLE', 'UNIT_FAIL', 'NO_UNIT',
'UNIT_NOTNEEDED', 'WANTED_NUMERIC', 'BAD_FORMULA', 'NOT_FUNCTION',
'WRONG_FORMAT', 'INTERNAL_ERROR',
'COMMA_FAIL', 'SIG_FAIL', 'INCORRECT', 'MISORDERED_RANK',
'INVALID_FILETYPE', 'EXCESS_FILESIZE', 'FILENAME_INUSE',
'DRAFT', 'SUBMITTED',
'SUBMITTED_CREDIT', 'ANONYMOUS', 'ANONYMOUS_CREDIT',
'ASSIGNED_SCORE', 'APPROX_ANS', 'EXACT_ANS');
my $i=0;
my %fwd_awards = map { ($_,$i++) } @awards;
my $max=scalar(@awards);
@awards=reverse(@awards);
$i=0;
my %rev_awards = map { ($_,$i++) } @awards;
sub awarddetail_to_awarded {
my ($awarddetail) = @_;
if ($awarddetail eq 'EXACT_ANS'
|| $awarddetail eq 'APPROX_ANS') {
return 1;
}
return 0;
}
sub hide_award {
my ($award) = @_;
if (&Apache::lonhomework::show_no_problem_status()) {
return 1;
}
if ($award =~
/^(?:EXACT_ANS|APPROX_ANS|SUBMITTED|SUBMITTED_CREDIT|ANONYMOUS|ANONYMOUS_CREDIT|ASSIGNED_SCORE|INCORRECT)/) {
return 1;
}
return 0;
}
sub finalizeawards {
my ($awardref,$msgref,$nameref,$reverse,$final_scantron)=@_;
my $result;
if ($#$awardref == -1) { $result = "NO_RESPONSE"; }
if ($result eq '' ) {
my $blankcount;
foreach my $award (@$awardref) {
if ($award eq '') {
$result='MISSING_ANSWER';
$blankcount++;
}
}
if ($blankcount == ($#$awardref + 1)) {
return ('NO_RESPONSE');
}
}
if ($Apache::lonxml::internal_error) { $result='INTERNAL_ERROR'; }
if (!$final_scantron && defined($result)) { return ($result); }
# if in scantron mode, if the award for any response is
# assigned score, then the part gets an assigned score
if ($final_scantron
&& grep {$_ eq 'ASSIGNED_SCORE'} (@$awardref)) {
return ('ASSIGNED_SCORE');
}
# if in scantron mode, if the award for any response is
# correct and there are non-correct responses,
# then the part gets an assigned score
if ($final_scantron
&& (grep { $_ eq 'EXACT_ANS' ||
$_ eq 'APPROX_ANS' } (@$awardref))
&& (grep { $_ ne 'EXACT_ANS' &&
$_ ne 'APPROX_ANS' } (@$awardref))) {
return ('ASSIGNED_SCORE');
}
# these awards are ordered from most important error through best correct
my $awards = (!$reverse) ? \%fwd_awards : \%rev_awards ;
my $best = $max;
my $j=0;
my $which;
foreach my $award (@$awardref) {
if ($awards->{$award} < $best) {
$best = $awards->{$award};
$which = $j;
}
$j++;
}
if (defined($which)) {
if (ref($nameref)) {
return ($$awardref[$which],$$msgref[$which],$$nameref[$which]);
} else {
return ($$awardref[$which],$$msgref[$which]);
}
}
return ('ERROR',undef);
}
}
sub decideoutput {
my ($award,$awarded,$awardmsg,$solved,$previous,$target,$nocorrect)=@_;
my $message='';
my $button=0;
my $previousmsg;
my $css_class='orange';
my $added_computer_text=0;
my %possible_class =
( 'correct' => 'LC_answer_correct',
'charged_try' => 'LC_answer_charged_try',
'not_charged_try' => 'LC_answer_not_charged_try',
'no_grade' => 'LC_answer_no_grade',
'no_message' => 'LC_no_message',
);
my $part = $Apache::inputtags::part;
my $tohandgrade = &Apache::lonnet::EXT("resource.$part.handgrade");
my $handgrade = ('yes' eq lc($tohandgrade));
#
# Should "Computer's Answer" be displayed?
# Should not be displayed if still answerable,
# if the problem is handgraded,
# or if the problem does not give a correct answer
#
my $computer = ($handgrade || $nocorrect)? ''
: " ".&mt("Computer's answer now shown above.");
&Apache::lonxml::debug("handgrade has :$handgrade:");
if ($previous) { $previousmsg=&mt('You have entered that answer before'); }
if ($solved =~ /^correct/) {
$css_class=$possible_class{'correct'};
$message=&mt('You are correct.');
if ($awarded < 1 && $awarded > 0) {
$message=&mt('You are partially correct.');
$css_class=$possible_class{'not_charged_try'};
} elsif ($awarded < 1) {
$message=&mt('Incorrect.');
$css_class=$possible_class{'charged_try'};
}
if ($env{'request.filename'} =~
m|/res/lib/templates/examupload.problem$|) {
$message = &mt("A score has been assigned.");
$added_computer_text=1;
} else {
if ($target eq 'tex') {
$message = '\textbf{'.$message.'}';
} else {
$message = "<b>".$message."</b>";
$message.= $computer;
}
$added_computer_text=1;
if ($awarded > 0) {
my ($symb) = &Apache::lonnet::whichuser();
if (($symb ne '')
&&
($env{'course.'.$env{'request.course.id'}.
'.disable_receipt_display'} ne 'yes') &&
($Apache::lonhomework::type ne 'practice')) {
$message.=(($target eq 'web')?'<br />':' ').
&mt('Your receipt no. is [_1]',
(&Apache::lonnet::receipt($Apache::inputtags::part).
(($target eq 'web')?&Apache::loncommon::help_open_topic('Receipt'):'')));
}
}
}
if ($awarded==1) { $button=0; } else { $button=1; }
$previousmsg='';
} elsif ($solved =~ /^excused/) {
if ($target eq 'tex') {
$message = ' \textbf{'.&mt('You are excused from the problem.').'} ';
} else {
$message = "<b>".&mt('You are excused from the problem.')."</b>";
}
$css_class=$possible_class{'charged_try'};
$button=0;
$previousmsg='';
} elsif ($award eq 'EXACT_ANS' || $award eq 'APPROX_ANS' ) {
if ($solved =~ /^incorrect/ || $solved eq '') {
$message = &mt("Incorrect").".";
$css_class=$possible_class{'charged_try'};
$button=1;
} else {
if ($target eq 'tex') {
$message = '\textbf{'.&mt('You are correct.').'}';
} else {
$message = "<b>".&mt('You are correct.')."</b>";
$message.= $computer;
}
$added_computer_text=1;
if ($awarded > 0
&& $env{'course.'.
$env{'request.course.id'}.
'.disable_receipt_display'} ne 'yes') {
$message.=(($target eq 'web')?'<br />':' ').
&mt('Your receipt is [_1]',
(&Apache::lonnet::receipt($Apache::inputtags::part).
(($target eq 'web')?&Apache::loncommon::help_open_topic('Receipt'):'')));
}
$css_class=$possible_class{'correct'};
$button=0;
$previousmsg='';
}
} elsif ($award eq 'NO_RESPONSE') {
$message = '';
$css_class=$possible_class{'no_feedback'};
$button=1;
} elsif ($award eq 'EXTRA_ANSWER') {
$message = &mt('Some extra items were submitted.');
$css_class=$possible_class{'not_charged_try'};
$button = 1;
} elsif ($award eq 'MISSING_ANSWER') {
$message = &mt('Some items were not submitted.');
if ($target ne 'tex') {
$message .= &Apache::loncommon::help_open_topic('Some_Items_Were_Not_Submitted');
}
$css_class=$possible_class{'not_charged_try'};
$button = 1;
} elsif ($award eq 'ERROR') {
$message = &mt('An error occurred while grading your answer.');
$css_class=$possible_class{'not_charged_try'};
$button = 1;
} elsif ($award eq 'TOO_LONG') {
$message = &mt("The submitted answer was too long.");
$css_class=$possible_class{'not_charged_try'};
$button=1;
} elsif ($award eq 'WANTED_NUMERIC') {
$message = &mt("This question expects a numeric answer.");
$css_class=$possible_class{'not_charged_try'};
$button=1;
} elsif ($award eq 'MISORDERED_RANK') {
$message = &mt('You have provided an invalid ranking.');
if ($target ne 'tex') {
$message.=' '.&mt('Please refer to [_1]',&Apache::loncommon::help_open_topic('Ranking_Problems',&mt('help on ranking problems')));
}
$css_class=$possible_class{'not_charged_try'};
$button=1;
} elsif ($award eq 'EXCESS_FILESIZE') {
$message = &mt('Submission won\'t be graded. The combined size of submitted files exceeded the amount allowed.');
$css_class=$possible_class{'not_charged_try'};
$button=1;
} elsif ($award eq 'FILENAME_INUSE') {
$message = &mt('You have already uploaded a file with that filename.');
if ($target eq 'tex') {
$message.= "\\\\\n";
} else {
$message .= '<br />';
}
$message .= &mt('Please use a different file name.');
$css_class=$possible_class{'not_charged_try'};
$button=1;
} elsif ($award eq 'INVALID_FILETYPE') {
$message = &mt("Submission won't be graded. The type of file submitted is not allowed.");
$css_class=$possible_class{'not_charged_try'};
$button=1;
} elsif ($award eq 'SIG_FAIL') {
my ($used,$min,$max)=split(':',$awardmsg);
my $word = ($used < $min) ? 'more' : 'fewer';
$message = &mt("Submission not graded. Use $word digits.",$used);
$css_class=$possible_class{'not_charged_try'};
$button=1;
} elsif ($award eq 'UNIT_INVALID_INSTRUCTOR') {
$message = &mt('Error in instructor specifed unit. This error has been reported to the instructor.', $awardmsg);
if ($target ne 'tex') {$message.=&Apache::loncommon::help_open_topic('Physical_Units');}
$css_class=$possible_class{'not_charged_try'};
$button=1;
} elsif ($award eq 'UNIT_INVALID_STUDENT') {
$message = &mt('Unable to interpret units. Computer reads units as "[_1]".',&markup_unit($awardmsg,$target));
if ($target ne 'tex') {$message.=&Apache::loncommon::help_open_topic('Physical_Units');}
$css_class=$possible_class{'not_charged_try'};
$button=1;
} elsif ($award eq 'UNIT_FAIL' || $award eq 'UNIT_IRRECONCIBLE') {
$message = &mt('Incompatible units. No conversion found between "[_1]" and the required units.',&markup_unit($awardmsg,$target));
if ($target ne 'tex') {$message.=&Apache::loncommon::help_open_topic('Physical_Units');}
$css_class=$possible_class{'not_charged_try'};
$button=1;
} elsif ($award eq 'UNIT_NOTNEEDED') {
$message = &mt('Only a number required. Computer reads units of "[_1]".',&markup_unit($awardmsg,$target));
$css_class=$possible_class{'not_charged_try'};
$button=1;
} elsif ($award eq 'NO_UNIT') {
$message = &mt("Units required").'.';
if ($target ne 'tex') {$message.=&Apache::loncommon::help_open_topic('Physical_Units')};
$css_class=$possible_class{'not_charged_try'};
$button=1;
} elsif ($award eq 'COMMA_FAIL') {
$message = &mt("Proper comma separation is required").'.';
$css_class=$possible_class{'not_charged_try'};
$button=1;
} elsif ($award eq 'BAD_FORMULA') {
$message = &mt("Unable to understand formula").'.';
if ($target ne 'tex') {$message.=&Apache::loncommon::help_open_topic('Formula_Answers')};
$css_class=$possible_class{'not_charged_try'};
$button=1;
} elsif ($award eq 'NOT_FUNCTION') {
$message = &mt("Not a function").'.';
$css_class=$possible_class{'not_charged_try'};
$button=1;
} elsif ($award eq 'WRONG_FORMAT') {
$message = &mt("Wrong format").'.';
$css_class=$possible_class{'not_charged_try'};
$button=1;
} elsif ($award eq 'INTERNAL_ERROR') {
$message = &mt("An internal error occurred while processing your answer. Please try again later.");
$css_class=$possible_class{'not_charged_try'};
$button=1;
} elsif ($award eq 'INCORRECT') {
$message = &mt("Incorrect").'.';
$css_class=$possible_class{'charged_try'};
$button=1;
} elsif ($award eq 'SUBMITTED') {
$message = &mt("Your submission has been recorded.");
$css_class=$possible_class{'no_grade'};
$button=1;
} elsif ($award eq 'SUBMITTED_CREDIT') {
$message = &mt("Your submission has been recorded, and credit awarded.");
$css_class=$possible_class{'correct'};
$button=1;
} elsif ($award eq 'ANONYMOUS') {
$message = &mt("Your anonymous submission has been recorded.");
$css_class=$possible_class{'no_grade'};
$button=1;
} elsif ($award eq 'ANONYMOUS_CREDIT') {
$message = &mt("Your anonymous submission has been recorded, and credit awarded.");
$css_class=$possible_class{'correct'};
} elsif ($award eq 'DRAFT') {
$message = &mt("Copy saved but not submitted.");
$css_class=$possible_class{'not_charged_try'};
$button=1;
} elsif ($award eq 'ASSIGNED_SCORE') {
$message = &mt("A score has been assigned.");
$css_class=$possible_class{'correct'};
$button=0;
} elsif ($award eq '') {
if ($handgrade && $Apache::inputtags::status[-1] eq 'SHOW_ANSWER') {
$message = &mt("Nothing submitted.");
$css_class=$possible_class{'charged_try'};
} else {
$css_class=$possible_class{'not_charged_try'};
}
$button=1;
} else {
$message = &mt("Unknown message").": $award";
$button=1;
}
my (undef,undef,$domain,$user)=&Apache::lonnet::whichuser();
foreach my $resid(@Apache::inputtags::response){
if ($Apache::lonhomework::history{"resource.$part.$resid.handback"}) {
if ($target eq 'tex') {
$message.= "\\\\\n";
} else {
$message.='<br />';
}
my @files = split(/\s*,\s*/,
$Apache::lonhomework::history{"resource.$part.$resid.handback"});
my $file_msg;
foreach my $file (@files) {
if ($target eq 'tex') {
$file_msg.= "\\\\\n".$file;
} else {
$file_msg.= '<br /><a href="/uploaded/'."$domain/$user".'/'.$file.'">'.$file.'</a>';
}
}
$message .= &mt('Returned file(s): [_1]',$file_msg);
if ($target eq 'tex') {
$message.= "\\\\\n";
} else {
$message.='<br />';
}
}
}
if (&Apache::lonhomework::hide_problem_status()
&& $Apache::inputtags::status[-1] ne 'SHOW_ANSWER'
&& &hide_award($award)) {
$message = &mt("Answer Submitted: Your final submission will be graded after the due date.");
$css_class=$possible_class{'no_grade'};
$button=1;
}
if ($Apache::inputtags::status[-1] eq 'SHOW_ANSWER' &&
!$added_computer_text && $target ne 'tex') {
$message.= $computer;
$added_computer_text=1;
}
if ($Apache::lonhomework::type eq 'practice') {
if ($target eq 'web') {
$message .= '<br />';
} else {
$message .= ' ';
}
$message.=&mt('Submissions to practice problems are not permanently recorded.');
}
return ($button,$css_class,$message,$previousmsg);
}
sub markup_unit {
my ($unit,$target)=@_;
if ($target eq 'tex') {
return '\texttt{'.&Apache::lonxml::latex_special_symbols($unit).'}';
} else {
return "<tt>".$unit."</tt>";
}
}
sub removealldata {
my ($id)=@_;
foreach my $key (keys(%Apache::lonhomework::results)) {
if (($key =~ /^resource\.\Q$id\E\./) && ($key !~ /\.collaborators$/)) {
&Apache::lonxml::debug("Removing $key");
delete($Apache::lonhomework::results{$key});
}
}
}
sub hidealldata {
my ($id)=@_;
foreach my $key (keys(%Apache::lonhomework::results)) {
if (($key =~ /^resource\.\Q$id\E\./) && ($key !~ /\.collaborators$/)) {
&Apache::lonxml::debug("Hidding $key");
my $newkey=$key;
$newkey=~s/^(resource\.\Q$id\E\.[^\.]+\.)(.*)$/${1}hidden${2}/;
$Apache::lonhomework::results{$newkey}=
$Apache::lonhomework::results{$key};
delete($Apache::lonhomework::results{$key});
}
}
}
sub setgradedata {
my ($award,$msg,$id,$previously_used) = @_;
if ($Apache::lonhomework::scantronmode &&
&Apache::lonnet::validCODE($env{'form.CODE'})) {
$Apache::lonhomework::results{"resource.CODE"}=$env{'form.CODE'};
} elsif ($Apache::lonhomework::scantronmode &&
$env{'form.CODE'} eq '' &&
$Apache::lonhomework::history{"resource.CODE"} ne '') {
$Apache::lonhomework::results{"resource.CODE"}='';
}
if (!$Apache::lonhomework::scantronmode &&
$Apache::inputtags::status['-1'] ne 'CAN_ANSWER' &&
$Apache::inputtags::status['-1'] ne 'CANNOT_ANSWER') {
$Apache::lonhomework::results{"resource.$id.afterduedate"}=$award;
return '';
} elsif ( $Apache::lonhomework::history{"resource.$id.awarded"} < 1
|| $Apache::lonhomework::scantronmode
|| &Apache::lonhomework::hide_problem_status() ) {
# the student doesn't already have it correct,
# or we are in a mode (scantron orno problem status) where a correct
# can become incorrect
# handle assignment of tries and solved status
my $solvemsg;
if ($Apache::lonhomework::scantronmode) {
$solvemsg='correct_by_scantron';
} else {
$solvemsg='correct_by_student';
}
if ($Apache::lonhomework::history{"resource.$id.afterduedate"}) {
$Apache::lonhomework::results{"resource.$id.afterduedate"}='';
}
if ( $award eq 'ASSIGNED_SCORE') {
$Apache::lonhomework::results{"resource.$id.tries"} =
$Apache::lonhomework::history{"resource.$id.tries"} + 1;
$Apache::lonhomework::results{"resource.$id.solved"} =
$solvemsg;
my $numawards=scalar(@Apache::inputtags::response);
$Apache::lonhomework::results{"resource.$id.awarded"} = 0;
foreach my $res (@Apache::inputtags::response) {
if (defined($Apache::lonhomework::results{"resource.$id.$res.awarded"})) {
$Apache::lonhomework::results{"resource.$id.awarded"}+=
$Apache::lonhomework::results{"resource.$id.$res.awarded"};
} else {
$Apache::lonhomework::results{"resource.$id.awarded"}+=
&awarddetail_to_awarded($Apache::lonhomework::results{"resource.$id.$res.awarddetail"});
}
}
if ($numawards > 0) {
$Apache::lonhomework::results{"resource.$id.awarded"}/=
$numawards;
}
} elsif ( $award eq 'APPROX_ANS' || $award eq 'EXACT_ANS' ) {
$Apache::lonhomework::results{"resource.$id.tries"} =
$Apache::lonhomework::history{"resource.$id.tries"} + 1;
$Apache::lonhomework::results{"resource.$id.solved"} =
$solvemsg;
$Apache::lonhomework::results{"resource.$id.awarded"} = '1';
} elsif ( $award eq 'SUBMITTED_CREDIT' ) {
$Apache::lonhomework::results{"resource.$id.tries"} =
$Apache::lonhomework::history{"resource.$id.tries"} + 1;
$Apache::lonhomework::results{"resource.$id.solved"} =
'credit_attempted';
$Apache::lonhomework::results{"resource.$id.awarded"} = '1';
} elsif ( $award eq 'ANONYMOUS_CREDIT' ) {
$Apache::lonhomework::results{"resource.$id.tries"} =
$Apache::lonhomework::history{"resource.$id.tries"} + 1;
$Apache::lonhomework::results{"resource.$id.solved"} =
'credit_attempted';
$Apache::lonhomework::results{"resource.$id.awarded"} = '1';
} elsif ( $award eq 'INCORRECT' ) {
$Apache::lonhomework::results{"resource.$id.tries"} =
$Apache::lonhomework::history{"resource.$id.tries"} + 1;
if (&Apache::lonhomework::hide_problem_status()
|| $Apache::lonhomework::scantronmode) {
$Apache::lonhomework::results{"resource.$id.awarded"} = 0;
}
$Apache::lonhomework::results{"resource.$id.solved"} =
'incorrect_attempted';
} elsif ( $award eq 'SUBMITTED' ) {
$Apache::lonhomework::results{"resource.$id.tries"} =
$Apache::lonhomework::history{"resource.$id.tries"} + 1;
$Apache::lonhomework::results{"resource.$id.solved"} =
'ungraded_attempted';
} elsif ( $award eq 'ANONYMOUS' ) {
$Apache::lonhomework::results{"resource.$id.tries"} =
$Apache::lonhomework::history{"resource.$id.tries"} + 1;
$Apache::lonhomework::results{"resource.$id.solved"} =
'ungraded_attempted';
} elsif ( $award eq 'DRAFT' ) {
$Apache::lonhomework::results{"resource.$id.solved"} = '';
} elsif ( $award eq 'NO_RESPONSE' ) {
#no real response so delete any data that got stored
&removealldata($id);
return '';
} else {
$Apache::lonhomework::results{"resource.$id.solved"} =
'incorrect_attempted';
if (&Apache::lonhomework::show_no_problem_status()
|| $Apache::lonhomework::scantronmode) {
$Apache::lonhomework::results{"resource.$id.tries"} =
$Apache::lonhomework::history{"resource.$id.tries"} + 1;
$Apache::lonhomework::results{"resource.$id.awarded"} = 0;
}
if (&Apache::lonhomework::show_some_problem_status()) {
# clear out the awarded if they had gotten it wrong/right
# and are now in an error mode
$Apache::lonhomework::results{"resource.$id.awarded"} = '';
}
}
if (defined($msg)) {
$Apache::lonhomework::results{"resource.$id.awardmsg"} = $msg;
}
# did either of the overall awards chage? If so ignore the
# previous check
if (($Apache::lonhomework::results{"resource.$id.awarded"} eq
$Apache::lonhomework::history{"resource.$id.awarded"}) &&
($Apache::lonhomework::results{"resource.$id.solved"} eq
$Apache::lonhomework::history{"resource.$id.solved"})) {
# check if this was a previous submission if it was delete the
# unneeded data and update the previously_used attribute
if ( $previously_used eq 'PREVIOUSLY_USED') {
if (&Apache::lonhomework::show_problem_status()) {
delete($Apache::lonhomework::results{"resource.$id.tries"});
$Apache::lonhomework::results{"resource.$id.previous"} = '1';
}
} elsif ( $previously_used eq 'PREVIOUSLY_LAST') {
#delete all data as they student didn't do anything, but save
#the list of collaborators.
&removealldata($id);
#and since they didn't do anything we were never here
return '';
} else {
$Apache::lonhomework::results{"resource.$id.previous"} = '0';
}
}
} elsif ( $Apache::lonhomework::history{"resource.$id.awarded"} == 1 ) {
#delete all data as they student already has it correct
&removealldata($id);
#and since they didn't do anything we were never here
return '';
}
$Apache::lonhomework::results{"resource.$id.award"} = $award;
if ($award eq 'SUBMITTED') {
&Apache::response::add_to_gradingqueue();
}
if (($Apache::lonhomework::type eq 'anonsurvey') ||
($Apache::lonhomework::type eq 'anonsurveycred') ||
($Apache::lonhomework::type eq 'randomizetry')) {
$Apache::lonhomework::results{"resource.$id.type"} = $Apache::lonhomework::type;
}
if ($Apache::lonhomework::type eq 'randomizetry') {
$Apache::lonhomework::results{"resource.$id.rndseed"} = $env{'form.'.$id.'.rndseed'};
}
}
sub find_which_previous {
my ($version) = @_;
my $part = $Apache::inputtags::part;
my (@previous_version);
foreach my $resp (@Apache::inputtags::response) {
my $key = "$version:resource.$part.$resp.submission";
my $submission = $Apache::lonhomework::history{$key};
my %previous = &Apache::response::check_for_previous($submission,
$part,$resp,
$version);
push(@previous_version,$previous{'version'});
}
return &previous_match(\@previous_version,
scalar(@Apache::inputtags::response));
}
sub previous_match {
my ($previous_array,$count) = @_;
my $match = 0;
my @matches;
foreach my $versionar (@$previous_array) {
foreach my $version (@$versionar) {
$matches[$version]++;
}
}
my $which=0;
foreach my $elem (@matches) {
if ($elem eq $count) {
$match=1;
last;
}
$which++;
}
return ($match,$which);
}
sub grade {
my ($target) = @_;
my $id = $Apache::inputtags::part;
my $response='';
if ( defined $env{'form.submitted'}) {
my (@awards,@msgs);
foreach $response (@Apache::inputtags::response) {
&Apache::lonxml::debug("looking for response.$id.$response.awarddetail");
my $value=$Apache::lonhomework::results{"resource.$id.$response.awarddetail"};
&Apache::lonxml::debug("keeping $value from $response for $id");
push (@awards,$value);
$value=$Apache::lonhomework::results{"resource.$id.$response.awardmsg"};
&Apache::lonxml::debug("got message $value from $response for $id");
push (@msgs,$value);
}
my ($finalaward,$msg) =
&finalizeawards(\@awards,\@msgs,undef,undef,
$Apache::lonhomework::scantronmode);
my $previously_used;
if ( $#Apache::inputtags::previous eq $#awards ) {
my ($match) =
&previous_match(\@Apache::inputtags::previous_version,
scalar(@Apache::inputtags::response));
if ($match) {
$previously_used = 'PREVIOUSLY_LAST';
foreach my $value (@Apache::inputtags::previous) {
if ($value eq 'PREVIOUSLY_USED' ) {
$previously_used = $value;
last;
}
}
}
}
&Apache::lonxml::debug("final award $finalaward, $previously_used, message $msg");
&setgradedata($finalaward,$msg,$id,$previously_used);
}
return '';
}
sub get_grade_messages {
my ($id,$prefix,$target,$status,$nocorrect) = @_;
# nocorrect suppresses "Computer's answer now shown above"
my ($message,$latemessage,$trystr,$previousmsg);
my $showbutton = 1;
my $award = $Apache::lonhomework::history{"$prefix.award"};
my $awarded = $Apache::lonhomework::history{"$prefix.awarded"};
my $solved = $Apache::lonhomework::history{"$prefix.solved"};
my $previous = $Apache::lonhomework::history{"$prefix.previous"};
my $awardmsg = $Apache::lonhomework::history{"$prefix.awardmsg"};
&Apache::lonxml::debug("Found Award |$award|$solved|$awardmsg");
if ( $award ne '' || $solved ne '' || $status eq 'SHOW_ANSWER') {
&Apache::lonxml::debug('Getting message');
($showbutton,my $css_class,$message,$previousmsg) =
&decideoutput($award,$awarded,$awardmsg,$solved,$previous,
$target,(($status eq 'CAN_ANSWER') || $nocorrect));
if ($target eq 'tex') {
$message='\vskip 2 mm '.$message.' ';
} else {
$message="<td class=\"$css_class\">$message</td>";
if ($previousmsg) {
$previousmsg="<td class=\"LC_answer_previous\">$previousmsg</td>";
}
}
}
my $tries = $Apache::lonhomework::history{"$prefix.tries"};
my $maxtries = &Apache::lonnet::EXT("resource.$id.maxtries");
&Apache::lonxml::debug("got maxtries of :$maxtries:");
#if tries are set to negative turn off the Tries/Button and messages
if (defined($maxtries) && $maxtries < 0) { return ''; }
if ( $tries eq '' ) { $tries = '0'; }
if ( $maxtries eq '' ) { $maxtries = '2'; }
if ( $maxtries eq 'con_lost' ) { $maxtries = '0'; }
my $tries_text= &get_tries_text();;
if ($showbutton) {
if ($target eq 'tex') {
if ($env{'request.state'} ne "construct"
&& $Apache::lonhomework::type ne 'exam'
&& $env{'form.suppress_tries'} ne 'yes') {
$trystr = ' {\vskip 1 mm \small \textit{'.$tries_text.'} '.
$tries.'/'.$maxtries.'} \vskip 2 mm ';
} else {
$trystr = '\vskip 0 mm ';
}
} else {
$trystr = '<td><span class="LC_nobreak">'.&mt($tries_text)." $tries";
if ($Apache::lonhomework::parsing_a_task) {
} elsif($env{'request.state'} ne 'construct') {
$trystr.="/".&Apache::lonhtmlcommon::direct_parm_link($maxtries,$env{'request.symb'},'maxtries',$id,$target);
} else {
if (defined($Apache::inputtags::params{'maxtries'})) {
$trystr.="/".$Apache::inputtags::params{'maxtries'};
}
}
$trystr.="</span></td>";
}
}
if ($Apache::lonhomework::history{"$prefix.afterduedate"}) {
#last submissions was after due date
$latemessage=&mt(' The last submission was after the Due Date ');;
if ($target eq 'web') {
$latemessage='<td class="LC_answer_late">'.$latemessage.'</td>';
}
}
return ($previousmsg,$latemessage,$message,$trystr,$showbutton);
}
sub gradestatus {
my ($id,$target,$no_previous) = @_;
my $showbutton = 1;
my $message = '';
my $latemessage = '';
my $trystr='';
my $button='';
my $previousmsg='';
my $status = $Apache::inputtags::status['-1'];
&Apache::lonxml::debug("gradestatus has :$status:");
if ( $status ne 'CLOSED'
&& $status ne 'UNAVAILABLE'
&& $status ne 'INVALID_ACCESS'
&& $status ne 'NEEDS_CHECKIN'
&& $status ne 'NOT_IN_A_SLOT') {
($previousmsg,$latemessage,$message,$trystr) =
&get_grade_messages($id,"resource.$id",$target,$status,
$showbutton);
if ( $status eq 'SHOW_ANSWER' || $status eq 'CANNOT_ANSWER') {
$showbutton = 0;
}
if ( $status eq 'SHOW_ANSWER') {
undef($previousmsg);
}
if ( $showbutton ) {
if ($target ne 'tex') {
$button =
'<input onmouseup="javascript:setSubmittedPart(\''.$id.'\');this.form.action+=\'#'.&escape($id).'\';"
type="submit" name="submit_'.$id.'"
value="'.&mt('Submit Answer').'" />';
}
}
}
my $output= $previousmsg.$latemessage.$message.$trystr;
if ($output =~ /^\s*$/) {
return $button;
} else {
if ($target eq 'tex') {
return $button.' \vskip 0 mm '.$output.' ';
} else {
$output =
'<table><tr><td>'.$button.'</td>'.$output;
if (!$no_previous) {
$output.='<td>'.&previous_tries($id,$target).'</td>';
}
$output.= '</tr></table>';
return $output;
}
}
}
sub previous_tries {
my ($id,$target) = @_;
my $output;
my $status = $Apache::inputtags::status['-1'];
my $count;
my %count_lookup;
my $lastrndseed;
foreach my $i (1..$Apache::lonhomework::history{'version'}) {
my $prefix = $i.":resource.$id";
my $is_anon;
if (defined($env{'form.grade_symb'})) {
if (($Apache::lonhomework::history{"$prefix.type"} eq 'anonsurvey') ||
($Apache::lonhomework::history{"$prefix.type"} eq 'anonsurveycred')) {
$is_anon = 1;
}
}
next if (!exists($Apache::lonhomework::history{"$prefix.award"}));
$count++;
$count_lookup{$i} = $count;
my $curr_rndseed = $Apache::lonhomework::history{"$prefix.rndseed"};
my ($previousmsg,$latemessage,$message,$trystr);
($previousmsg,$latemessage,$message,$trystr) =
&get_grade_messages($id,"$prefix",$target,$status);
if ($previousmsg ne '') {
my ($match,$which) = &find_which_previous($i);
$message=$previousmsg;
my $previous = $count_lookup{$which};
$message =~ s{(</td>)}{ as submission \# $previous $1};
} elsif ($Apache::lonhomework::history{"$prefix.tries"}) {
if (!(&Apache::lonhomework::hide_problem_status()
&& $Apache::inputtags::status[-1] ne 'SHOW_ANSWER')
&& $Apache::lonhomework::history{"$prefix.solved"} =~/^correct/
) {
my $txt_correct = &mt('Correct');
my $awarded = $Apache::lonhomework::history{"$prefix.awarded"};
if ($awarded < 1 && $awarded > 0) {
$txt_correct=&mt('Partially Correct');
} elsif ($awarded < 1) {
if ($awarded eq '') {
$txt_correct='';
} else {
$txt_correct=&mt('Incorrect');
}
}
$message =~ s{(<td.*?>)(.*?)(</td>)}
{$1 <strong>$txt_correct</strong>. $3}s;
}
my $trystr = "(".&mt('Try [_1]',$Apache::lonhomework::history{"$prefix.tries"}).")";
if ($curr_rndseed || $lastrndseed) {
if ($curr_rndseed ne $lastrndseed) {
$trystr .= '<br /><span style="color: green; white-space: nowrap; font-style: italic; font-weight: bold; font-size: 80%;">'.&mt('New problem variation this try.').'</span>';
}
}
$message =~ s{(</td>)}{ $trystr $1};
}
my ($class) = ($message =~ m{<td.*class="([^"]*)"}); #"
$message =~ s{(<td.*?>)}{<td>};
$output.='<tr class="'.$class.'">';
$output.='<td align="center">'.$count.'</td>';
$output.=$message;
foreach my $resid (@Apache::inputtags::response) {
my $prefix = $prefix.".$resid";
if (exists($Apache::lonhomework::history{"$prefix.submission"})) {
my $submission =
$Apache::inputtags::submission_display{"$prefix.submission"};
if (!defined($submission)) {
$submission =
$Apache::lonhomework::history{"$prefix.submission"};
}
if ($is_anon) {
$output.='<td>'.&mt('(only shown to submitter)').'</td>';
} else {
$output.='<td>'.$submission.'</td>';
}
} else {
$output.='<td></td>';
}
}
$output.=&Apache::loncommon::end_data_table_row()."\n";
$lastrndseed = $curr_rndseed;
}
return if ($output eq '');
my $headers =
'<tr>'.'<th>'.&mt('Submission #').'</th><th>'.&mt('Try').
'</th><th colspan="'.scalar(@Apache::inputtags::response).'">'.
&mt('Submitted Answer').'</th>';
$output ='<table class="LC_prior_tries">'.$headers.$output.'</table>';
#return $output;
$output = &Apache::loncommon::js_ready($output);
$output.='<br /><form action=""><center><input type="button" name="close" value="'.&mt('Close Window').'" onClick="window.close()" /></center></form>';
my $windowopen=&Apache::lonhtmlcommon::javascript_docopen();
my $tries_text = &get_tries_text('link');
my $start_page =
&Apache::loncommon::start_page($tries_text, undef,
{'only_body' => 1,
'bgcolor' => '#FFFFFF',
'js_ready' => 1,
'inherit_jsmath' => 1, });
my $end_page =
&Apache::loncommon::end_page({'js_ready' => 1,});
my $prefix = $env{'form.request.prefix'};
$prefix =~ tr{.}{_};
my $function_name = "LONCAPA_previous_tries_".$prefix.
$Apache::lonxml::curdepth.'_'.$env{'form.counter'};
my $result ="<script type=\"text/javascript\">
// <![CDATA[
function $function_name() {newWindow=open('','new_W','width=500,height=500,scrollbars=1,resizable=yes');newWindow.$windowopen;newWindow.document.writeln('$start_page $output $end_page');newWindow.document.close();newWindow.focus()}
// ]]>
</script><a href=\"javascript:$function_name();void(0);\">".&mt($tries_text)."</a><br />";
#use Data::Dumper;
#&Apache::lonnet::logthis(&Dumper(\%Apache::inputtags::submission_display));
return $result;
}
sub get_tries_text {
my ($context) = @_;
my $tries_text;
if ($context eq 'link') {
$tries_text = 'Previous Tries';
} else {
$tries_text = 'Tries';
}
if ( $Apache::lonhomework::type eq 'survey' ||
$Apache::lonhomework::type eq 'surveycred' ||
$Apache::lonhomework::type eq 'anonsurvey' ||
$Apache::lonhomework::type eq 'anonsurveycred' ||
$Apache::lonhomework::parsing_a_task) {
if ($context eq 'link') {
$tries_text = 'Previous Submissions';
} else {
$tries_text = 'Submissions';
}
}
return $tries_text;
}
1;
__END__
=pod
=back
=cut
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>