# The LearningOnline Network with CAPA
# input definitons
#
# $Id: inputtags.pm,v 1.201 2006/07/14 18:17:58 albertel 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/
package Apache::inputtags;
use HTML::Entities();
use strict;
use Apache::loncommon;
use Apache::lonlocal;
use Apache::lonnet;
use lib '/home/httpd/lib/perl/';
use LONCAPA;
BEGIN {
&Apache::lonxml::register('Apache::inputtags',('hiddenline','textfield','textline'));
}
# 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.
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=();
}
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_param('id',$parstack,$safeeval);
if ($id eq '') { $id = $Apache::lonxml::curdepth; }
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--;
if ($Apache::inputtags::status[-1] eq 'CAN_ANSWER') {
my $partid=$Apache::inputtags::part;
my $oldresponse = &HTML::Entities::encode($Apache::lonhomework::history{"resource.$partid.$resid.submission"},'<>&"');
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);
}
&Apache::lonhtmlcommon::add_htmlareafields('HWVAL_'.$resid);
$result.= '<textarea wrap="hard" name="HWVAL_'.$resid.'" id="HWVAL_'.$resid.'" '.
"rows=\"$rows\" cols=\"$cols\">".$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 {
#right or wrong don't show it
#$result='<table border="1"><tr><td><i>'.$oldresponse.'</i></td></tr></table>';
$result='';
#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 = "";
if ($target eq 'web') {
$Apache::lonxml::evaluate--;
my $partid=$Apache::inputtags::part;
my $id=$Apache::inputtags::response[-1];
if ($Apache::inputtags::status[-1] eq 'CAN_ANSWER'
|| lc($Apache::lonhomework::problemstatus) eq 'no'
|| ($Apache::inputtags::status[-1] eq 'CANNOT_ANSWER'
&& $Apache::lonhomework::history{"resource.$partid.solved"} !~ /^correct/ )) {
my $size = &Apache::lonxml::get_param('size',$parstack,$safeeval);
my $maxlength;
if ($size eq '') { $size=20; } else {
if ($size < 20) { $maxlength=$size; }
}
my $oldresponse = &HTML::Entities::encode($Apache::lonhomework::history{"resource.$partid.$id.submission"},'<>&"');
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 type="text" '.$readonly.' name="'.$name.'" value="'.
$oldresponse.'" size="'.$size.'" maxlength="'.$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.
$result='<b>'.$Apache::inputtags::answertxt{$id}.'</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';}
$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'); }
return "";
}
sub start_hiddenline {
my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
my $result = "";
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 = &HTML::Entities::encode($Apache::lonhomework::history{"resource.$partid.$id.submission"},'<>&"');
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'); }
return "";
}
# $part -> partid
# $id -> responseid
# $uploadefiletypes -> comma seperated list of extensions allowed or * for any
# $which -> 'uploadedonly' -> 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
# returns a table row <tr>
sub file_selector {
my ($part,$id,$uploadedfiletypes,$which,$extratext)=@_;
if (!$uploadedfiletypes) { return ''; }
my $jspart=$part;
$jspart=~s/\./_/g;
my $result;
$result.='<tr><td>';
if ($uploadedfiletypes ne '*') {
$result.=
&mt('Allowed filetypes: <b>[_1]</b>',$uploadedfiletypes).'<br />';
}
if ($which eq 'uploadonly' || $which eq 'both') {
$result.=&mt('Submit a file: (only one file can be uploaded)').
' <br /><input type="file" size="50" name="HWFILE'.
$jspart.'_'.$id.'" /><br />';
my $uploadedfile= &HTML::Entities::encode($Apache::lonhomework::history{"resource.$part.$id.uploadedfile"},'<>&"');
if ($uploadedfile) {
my $url=$Apache::lonhomework::history{"resource.$part.$id.uploadedurl"};
&Apache::lonxml::extlink($url);
&Apache::lonnet::allowuploaded('/adm/essayresponse',$url);
my $icon=&Apache::loncommon::icon($url);
my $curfile='<a href="'.$url.'"><img src="'.$icon.
'" border="0" />'.$uploadedfile.'</a>';
$result.=&mt('Currently submitted: <tt>[_1]</tt>',$curfile);
} else {
#$result.=&mt('(Hand in a file you have prepared on your computer)');
}
}
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=HWPORT'.$jspart.'_'.$id.'","cat","height=600,width=800,scrollbars=1,resizable=1,menubar=2,location=1"))'."'".'>'.
&mt('Select Portfolio Files').'</a><br />'.
'<input type="text" size="50" name="HWPORT'.$jspart.'_'.$id.'" value="" />'.
'<br />';
if ($Apache::lonhomework::history{"resource.$part.$id.portfiles"}=~/[^\s]/){
my (@file_list,@bad_file_list);
foreach my $file (split(/\s*,\s*/,&unescape($Apache::lonhomework::history{"resource.$part.$id.portfiles"}))) {
my (undef,undef,$domain,$user)=&Apache::lonxml::whichuser();
my $url="/uploaded/$domain/$user/portfolio$file";
my $icon=&Apache::loncommon::icon($url);
push(@file_list,'<a href="'.$url.'"><img src="'.$icon.
'" border="0" />'.$file.'</a>');
if (! &Apache::lonnet::stat_file($url)) {
&Apache::lonnet::logthis("bad file is $url");
push(@bad_file_list,'<a href="'.$url.'"><img src="'.$icon.
'" border="0" />'.$file.'</a>');
}
}
my $files = '<span class="LC_filename">'.
join('</span>, <span class="LC_filename">',@file_list).
'</span>';
$result.=&mt("Portfolio files previously selected: [_1]",$files);
if (@bad_file_list) {
my $bad_files = '<span class="LC_filename">'.
join('</span>, <span class="LC_filename">',@bad_file_list).
'</span>';
$result.='<br />'.&mt('<span class="LC_error">These file(s) don\'t exist:</span> [_1]',$bad_files);
}
}
}
$result.='</td></tr>';
return $result;
}
sub checkstatus {
my ($value,$awardref,$msgref)=@_;
for (my $i=0;$i<=$#$awardref;$i++) {
if ($$awardref[$i] eq $value) {
return ($$awardref[$i],$$msgref[$i]);
}
}
return(undef,undef);
}
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', 'SIG_FAIL', 'INCORRECT',
'MISORDERED_RANK', 'INVALID_FILETYPE',
'DRAFT', 'SUBMITTED', 'ASSIGNED_SCORE',
'APPROX_ANS', 'EXACT_ANS','COMMA_FAIL') {
if ($award eq $possibleaward) { return 1; }
}
return 0;
}
sub finalizeawards {
my ($awardref,$msgref,$nameref,$reverse)=@_;
my $result=undef;
my $award;
my $msg;
if ($#$awardref == -1) { $result = "NO_RESPONSE"; }
if ($result eq '' ) {
my $blankcount;
foreach $award (@$awardref) {
if ($award eq '') {
$result='MISSING_ANSWER';
$blankcount++;
}
}
if ($blankcount == ($#$awardref + 1)) { $result = 'NO_RESPONSE'; }
}
if (defined($result)) { return ($result,$msg); }
# these awards are ordered from most important error through best correct
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',
'COMMA_FAIL', 'SIG_FAIL', 'INCORRECT', 'MISORDERED_RANK',
'INVALID_FILETYPE', 'DRAFT', 'SUBMITTED', 'ASSIGNED_SCORE',
'APPROX_ANS', 'EXACT_ANS');
if ($reverse) { @awards=reverse(@awards); }
foreach my $possibleaward (@awards) {
($result,$msg)=&checkstatus($possibleaward,$awardref,$msgref);
if (defined($result)) { return ($result,$msg); }
}
return ('ERROR',undef);
}
sub decideoutput {
my ($award,$awarded,$awardmsg,$solved,$previous,$target)=@_;
my $message='';
my $button=0;
my $previousmsg;
my $bgcolor='orange';
my $added_computer_text=0;
my %possiblecolors =
( 'correct' => '#aaffaa',
'charged_try' => '#ffaaaa',
'not_charged_try' => '#ffffaa',
'no_grade' => '#ffffaa',
'no_message' => '#ffffff',
);
my $part = $Apache::inputtags::part;
my $handgrade =
('yes' eq lc(&Apache::lonnet::EXT("resource.$part.handgrade")));
my $computer = ($handgrade)? ''
: " ".&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/) {
$bgcolor=$possiblecolors{'correct'};
$message=&mt('You are correct.');
if ($awarded < 1 && $awarded > 0) {
$message=&mt('You are partially correct.');
$bgcolor=$possiblecolors{'not_charged_try'};
} elsif ($awarded < 1) {
$message=&mt('Incorrect.');
$bgcolor=$possiblecolors{'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;
unless ($env{'course.'.
$env{'request.course.id'}.
'.disable_receipt_display'} eq 'yes') {
$message.=(($target eq 'web')?'<br />':' ').
&mt('Your receipt is').' '.&Apache::lonnet::receipt($Apache::inputtags::part).
(($target eq 'web')?&Apache::loncommon::help_open_topic('Receipt'):'');
}
}
$button=0;
$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>";
}
$bgcolor=$possiblecolors{'charged_try'};
$button=0;
$previousmsg='';
} elsif ($award eq 'EXACT_ANS' || $award eq 'APPROX_ANS' ) {
if ($solved =~ /^incorrect/ || $solved eq '') {
$message = &mt("Incorrect").".";
$bgcolor=$possiblecolors{'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;
unless ($env{'course.'.
$env{'request.course.id'}.
'.disable_receipt_display'} eq 'yes') {
$message.=(($target eq 'web')?'<br />':' ').
'Your receipt is '.&Apache::lonnet::receipt($Apache::inputtags::part).
(($target eq 'web')?&Apache::loncommon::help_open_topic('Receipt'):'');
}
$bgcolor=$possiblecolors{'correct'};
$button=0;
$previousmsg='';
}
} elsif ($award eq 'NO_RESPONSE') {
$message = '';
$bgcolor=$possiblecolors{'no_feedback'};
$button=1;
} elsif ($award eq 'EXTRA_ANSWER') {
$message = &mt('Some extra items were submitted.');
$bgcolor=$possiblecolors{'not_charged_try'};
$button = 1;
} elsif ($award eq 'MISSING_ANSWER') {
$message = &mt('Some items were not submitted.');
$bgcolor=$possiblecolors{'not_charged_try'};
$button = 1;
} elsif ($award eq 'ERROR') {
$message = &mt('An error occured while grading your answer.');
$bgcolor=$possiblecolors{'not_charged_try'};
$button = 1;
} elsif ($award eq 'TOO_LONG') {
$message = &mt("The submitted answer was too long.");
$bgcolor=$possiblecolors{'not_charged_try'};
$button=1;
} elsif ($award eq 'WANTED_NUMERIC') {
$message = &mt("This question expects a numeric answer.");
$bgcolor=$possiblecolors{'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').' '.&Apache::loncommon::help_open_topic('Ranking_Problems','help on ranking problems');
}
$bgcolor=$possiblecolors{'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.');
$bgcolor=$possiblecolors{'not_charged_try'};
$button=1;
} elsif ($award eq 'SIG_FAIL') {
my ($used,$min,$max)=split(':',$awardmsg);
my $word;
if ($used < $min) { $word=&mt('more'); }
if ($used > $max) { $word=&mt('fewer'); }
$message = &mt("Submission not graded. Use [_2] digits.",$used,$word);
$bgcolor=$possiblecolors{'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');}
$bgcolor=$possiblecolors{'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');}
$bgcolor=$possiblecolors{'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');}
$bgcolor=$possiblecolors{'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));
$bgcolor=$possiblecolors{'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')};
$bgcolor=$possiblecolors{'not_charged_try'};
$button=1;
} elsif ($award eq 'COMMA_FAIL') {
$message = &mt("Proper comma separation is required").'.';
$bgcolor=$possiblecolors{'not_charged_try'};
$button=1;
} elsif ($award eq 'BAD_FORMULA') {
$message = &mt("Unable to understand formula");
$bgcolor=$possiblecolors{'not_charged_try'};
$button=1;
} elsif ($award eq 'INCORRECT') {
$message = &mt("Incorrect").'.';
$bgcolor=$possiblecolors{'charged_try'};
$button=1;
} elsif ($award eq 'SUBMITTED') {
$message = &mt("Your submission has been recorded.");
$bgcolor=$possiblecolors{'no_grade'};
$button=1;
} elsif ($award eq 'DRAFT') {
$message = &mt("A draft copy has been saved.");
$bgcolor=$possiblecolors{'not_charged_try'};
$button=1;
} elsif ($award eq 'ASSIGNED_SCORE') {
$message = &mt("A score has been assigned.");
$bgcolor=$possiblecolors{'correct'};
$button=0;
} elsif ($award eq '') {
if ($handgrade && $Apache::inputtags::status[-1] eq 'SHOW_ANSWER') {
$message = &mt("Nothing submitted.");
$bgcolor=$possiblecolors{'charged_try'};
} else {
$bgcolor=$possiblecolors{'not_charged_try'};
}
$button=1;
} else {
$message = &mt("Unknown message").": $award";
$button=1;
}
my (undef,undef,$domain,$user)=&Apache::lonxml::whichuser();
foreach my $resid(@Apache::inputtags::response){
if ($Apache::lonhomework::history{"resource.$part.$resid.handback"}) {
$message.='<br />';
my @files = split(/\s*,\s*/,
$Apache::lonhomework::history{"resource.$part.$resid.handback"});
my $file_msg;
foreach my $file (@files) {
$file_msg.= '<br /><a href="/uploaded/'."$domain/$user".'/'.$file.'">'.$file.'</a>';
}
$message .= &mt('Returned file(s): [_1]',$file_msg);
}
}
if (lc($Apache::lonhomework::problemstatus) eq 'no' &&
$Apache::inputtags::status[-1] ne 'SHOW_ANSWER') {
$message = &mt("Answer Submitted: Your final submission will be graded after the due date.");
$bgcolor=$possiblecolors{'no_grade'};
$button=1;
}
if ($Apache::inputtags::status[-1] eq 'SHOW_ANSWER' &&
!$added_computer_text && $target ne 'tex') {
$message.= $computer;
$added_computer_text=1;
}
return ($button,$bgcolor,$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.solved"} !~
/^correct/ || $Apache::lonhomework::scantronmode ||
lc($Apache::lonhomework::problemstatus) eq 'no') {
# 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) {
$Apache::lonhomework::results{"resource.$id.awarded"}+=
$Apache::lonhomework::results{"resource.$id.$res.awarded"};
}
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 'INCORRECT' ) {
$Apache::lonhomework::results{"resource.$id.tries"} =
$Apache::lonhomework::history{"resource.$id.tries"} + 1;
if (lc($Apache::lonhomework::problemstatus) eq 'no' ||
$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 '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 (lc($Apache::lonhomework::problemstatus) eq 'no' ||
$Apache::lonhomework::scantronmode) {
$Apache::lonhomework::results{"resource.$id.tries"} =
$Apache::lonhomework::history{"resource.$id.tries"} + 1;
$Apache::lonhomework::results{"resource.$id.awarded"} = 0;
}
}
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 (lc($Apache::lonhomework::problemstatus) ne 'no') {
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.solved"} =~
/^correct/ ) {
#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();
}
}
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);
my $previously_used;
if ( $#Apache::inputtags::previous eq $#awards ) {
my $match=0;
my @matches;
foreach my $versionar (@Apache::inputtags::previous_version) {
foreach my $version (@$versionar) {
$matches[$version]++;
}
}
foreach my $elem (@matches) {if ($elem eq ($#awards+1)) {$match=1;}}
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 gradestatus {
my ($id,$target) = @_;
my $showbutton = 1;
my $bgcolor = '';
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') {
my $award = $Apache::lonhomework::history{"resource.$id.award"};
my $awarded = $Apache::lonhomework::history{"resource.$id.awarded"};
my $solved = $Apache::lonhomework::history{"resource.$id.solved"};
my $previous = $Apache::lonhomework::history{"resource.$id.previous"};
my $awardmsg = $Apache::lonhomework::history{"resource.$id.awardmsg"};
&Apache::lonxml::debug("Found Award |$award|$solved|$awardmsg");
if ( $award ne '' || $solved ne '' || $status eq 'SHOW_ANSWER') {
&Apache::lonxml::debug('Getting message');
($showbutton,$bgcolor,$message,$previousmsg) =
&decideoutput($award,$awarded,$awardmsg,$solved,$previous,
$target);
if ($target eq 'tex') {
$message='\vskip 2 mm '.$message.' ';
} else {
$message="<td bgcolor=\"$bgcolor\">$message</td>";
if ($previousmsg) {
$previousmsg="<td bgcolor=\"#aaaaff\">$previousmsg</td>";
}
}
}
my $tries = $Apache::lonhomework::history{"resource.$id.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=&mt('Tries');
if ( $Apache::lonhomework::type eq 'survey' ||
$Apache::lonhomework::parsing_a_task) {
$tries_text=&mt('Submissions');
}
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><nobr>".$tries_text." $tries";
if ($Apache::lonhomework::parsing_a_task) {
} elsif($env{'request.state'} ne 'construct') {
$trystr.="/$maxtries";
} else {
if (defined($Apache::inputtags::params{'maxtries'})) {
$trystr.="/".$Apache::inputtags::params{'maxtries'};
}
}
$trystr.="</nobr></td>";
}
}
if ( $status eq 'SHOW_ANSWER' || $status eq 'CANNOT_ANSWER') {$showbutton = 0;}
if ( $showbutton ) {
if ($target ne 'tex') {
$button = '<input type="submit" name="submit_'.$id.'" value="'.&mt('Submit Answer').'" />';
}
}
if ($Apache::lonhomework::history{"resource.$id.afterduedate"}) {
#last submissions was after due date
$latemessage=&mt(' The last submission was after the Due Date ');;
if ($target eq 'web') {
$latemessage='<td bgcolor="#ffaaaa">'.$latemessage.'</td>';
}
}
}
my $output= $previousmsg.$latemessage.$message.$trystr;
if ($output =~ /^\s*$/) {
return $button;
} else {
if ($target eq 'tex') {
return $button.' \vskip 0 mm '.$output.' ';
} else {
return '<table><tr><td>'.$button.'</td>'.$output.'</tr></table>';
}
}
}
1;
__END__
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>