--- loncom/homework/response.pm 2011/12/15 01:21:28 1.230 +++ loncom/homework/response.pm 2024/12/25 02:31:06 1.251 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # various response type definitons response definition # -# $Id: response.pm,v 1.230 2011/12/15 01:21:28 raeburn Exp $ +# $Id: response.pm,v 1.251 2024/12/25 02:31:06 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -42,7 +42,7 @@ described at http://www.lon-capa.org. =over -=item +=item =back @@ -56,6 +56,7 @@ use Apache::lonnet; use Apache::inputtags(); use Apache::lonmaxima(); use Apache::lonr(); +use Apache::lontexconvert(); BEGIN { &Apache::lonxml::register('Apache::response',('responseparam','parameter','dataresponse','customresponse','mathresponse')); @@ -72,7 +73,7 @@ sub start_response { push (@Apache::inputtags::response,$id); push (@Apache::inputtags::responselist,$id); @Apache::inputtags::inputlist=(); - if ($Apache::inputtags::part eq '' && + if ($Apache::inputtags::part eq '' && !$Apache::lonhomework::ignore_response_errors) { &Apache::lonxml::error(&HTML::Entities::encode(&mt("Found a <*response> outside of a in a ed problem"),'<>&"')); } @@ -140,7 +141,7 @@ sub setrandomnumber { my ($ignore_id2,$target,$rndseed) = @_; if (!defined($rndseed)) { $rndseed=&Apache::structuretags::setup_rndseed(undef,$target); - } + } if (!defined($rndseed)) { $rndseed=&Apache::lonnet::rndseed(); } &Apache::lonxml::debug("randseed $rndseed"); # $rndseed=unpack("%32i",$rndseed); @@ -162,7 +163,7 @@ sub setrandomnumber { } else { $shift_amt=0; } - } + } &Apache::lonxml::debug("id1: $id1, id2: $id2, shift_amt: $shift_amt"); if (!$rand_alg || $rand_alg eq '32bit' || $rand_alg eq '64bit' || $rand_alg eq '64bit2') { @@ -180,7 +181,6 @@ sub setrandomnumber { } else { ($rndmod,$rndmod2)=&Apache::lonnet::digest("$id1,$id2"); } - $Apache::lonhomework::results{'resource.'.$id1.'.rawrndseed'}=$rndseed; if ($rndseed =~/([,:])/) { my $char=$1; use integer; @@ -197,7 +197,6 @@ sub setrandomnumber { } } &Apache::lonxml::debug("randseed $rndmod $rndseed"); - $Apache::lonhomework::results{'resource.'.$id1.'.rndseed'}=$rndseed; &Apache::lonnet::setup_random_from_rndseed($rndseed); return ''; } @@ -266,10 +265,15 @@ sub mandatory_part_meta { } sub meta_part_order { + my ($type) = @_; if (@Apache::inputtags::partlist) { my @parts=@Apache::inputtags::partlist; - shift(@parts); + unless ($type eq 'library') { + shift(@parts); + } return ''.join(',',@parts).''."\n"; + } elsif ($type eq 'library') { + return ''."\n"; } else { return '0'."\n"; } @@ -399,7 +403,7 @@ sub end_dataresponse { $Apache::lonhomework::results{"resource.$partid.$id.awarddetail"}='SUBMITTED'; } } else { - $result='Not Permitted to change values.' + $result=&mt('Not Permitted to change values'); } } } @@ -451,7 +455,7 @@ sub end_customresponse { if ($Apache::lonhomework::type eq 'exam' || &Apache::response::submitted('scantron')) { &Apache::response::scored_response($part,$id); - } elsif ( $response =~ /[^\s]/ && + } elsif ( $response =~ /[^\s]/ && $Apache::response::custom_answer_type[-1] eq 'loncapa/perl') { if (!$Apache::lonxml::default_homework_loaded) { &Apache::lonxml::default_homework_load($safeeval); @@ -463,12 +467,24 @@ sub end_customresponse { my $error; ${$safeeval->varglob('LONCAPA::customresponse_submission')}= $response; - + my ($award,$score) = &Apache::run::run('{ my $submission=$LONCAPA::customresponse_submission;'.$Apache::response::custom_answer[-1].'}',$safeeval); if (!&Apache::inputtags::valid_award($award)) { $error = $award; $award = 'ERROR'; } + if (($award eq 'INCORRECT') || ($award eq 'APPROX_ANS') || + ($award eq 'EXACT_ANS') || ($award eq 'ASSIGNED_SCORE')) { + if ($Apache::lonhomework::type eq 'survey') { + $award='SUBMITTED'; + } elsif ($Apache::lonhomework::type eq 'surveycred') { + $award='SUBMITTED_CREDIT'; + } elsif ($Apache::lonhomework::type eq 'anonsurvey') { + $award='ANONYMOUS'; + } elsif ($Apache::lonhomework::type eq 'anonsurveycred') { + $award='ANONYMOUS_CREDIT'; + } + } &Apache::response::handle_previous(\%previous,$award); $Apache::lonhomework::results{"resource.$part.$id.awarddetail"}= $award; @@ -493,7 +509,7 @@ sub end_customresponse { if ($target eq 'web') { &setup_prior_tries_hash(\&format_prior_response_custom); } - if ($target eq 'grade' || $target eq 'web' || $target eq 'answer' || + if ($target eq 'grade' || $target eq 'web' || $target eq 'answer' || $target eq 'tex' || $target eq 'analyze') { my $repetition = &repetition(); &Apache::lonxml::increment_counter($repetition,"$part.$id"); @@ -502,6 +518,9 @@ sub end_customresponse { &Apache::lonhomework::set_bubble_lines(); } } + if ($target eq 'web') { + &setup_prior_tries_hash(\&format_prior_response_math); + } pop(@Apache::lonxml::namespace); pop(@Apache::response::custom_answer); pop(@Apache::response::custom_answer_type); @@ -564,23 +583,6 @@ sub start_mathresponse { return $result; } -sub edit_mathresponse_button { - my ($id,$field)=@_; - my $button=&mt('Edit Answer'); -# my $helplink=&Apache::loncommon::help_open_topic('Formula_Editor'); - my $iconpath=$Apache::lonnet::perlvar{'lonIconsURL'}; - return(< -function edit_${id}_${field} (textarea) { - thenumber = textarea; - thedata = document.forms['lonhomework'].elements[textarea].value; - newwin = window.open("/adm/dragmath/applet/MaximaPopup.html","","width=565,height=400,resizable"); -} - -$button -ENDFORMULABUTTON -} - sub end_mathresponse { my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; my $result; @@ -614,6 +616,18 @@ sub end_mathresponse { $error = $award; $award = 'ERROR'; } + if (($award eq 'INCORRECT' || $award eq 'APPROX_ANS' || + $award eq 'EXACT_ANS')) { + if ($Apache::lonhomework::type eq 'survey') { + $award='SUBMITTED'; + } elsif ($Apache::lonhomework::type eq 'surveycred') { + $award='SUBMITTED_CREDIT'; + } elsif ($Apache::lonhomework::type eq 'anonsurvey') { + $award='ANONYMOUS'; + } elsif ($Apache::lonhomework::type eq 'anonsurveycred') { + $award='ANONYMOUS_CREDIT'; + } + } &Apache::response::handle_previous(\%previous,$award); $Apache::lonhomework::results{"resource.$part.$id.awarddetail"}= $award; @@ -623,15 +637,6 @@ sub end_mathresponse { } } } - if ($target eq 'web') { - &setup_prior_tries_hash(\&format_prior_response_math); - my $partid = $Apache::inputtags::part; - my $id = $Apache::inputtags::response[-1]; - if (($Apache::inputtags::status['-1'] eq 'CAN_ANSWER') - && (&Apache::lonnet::EXT('resource.'.$partid.'_'.$id.'.turnoffeditor') ne 'yes')) { - $result.=&edit_mathresponse_button($id,"HWVAL_$id"); - } - } pop(@Apache::lonxml::namespace); pop(@Apache::response::custom_answer); @@ -766,7 +771,8 @@ sub start_responseparam { } } elsif ($target eq 'grade' || $target eq 'answer' || $target eq 'web' || $target eq 'tex' || $target eq 'analyze' ) { - if ($env{'request.state'} eq 'construct') { + if (($env{'request.state'} eq 'construct') || + ($env{'request.noversionuri'} =~ m{^\Q/res/adm/includes/templates/\E[^/]+\.problem$})) { my $name =&Apache::lonxml::get_param('name',$parstack,$safeeval); my $default=&Apache::lonxml::get_param('default',$parstack, $safeeval); @@ -797,7 +803,10 @@ sub reset_params { sub setup_params { my ($tag,$safeeval) = @_; - if ($env{'request.state'} eq 'construct') { return; } + if (($env{'request.state'} eq 'construct') || + ($env{'request.noversionuri'} =~ m{^\Q/res/adm/includes/templates/\E[^/]+\.problem$})) { + return; + } my %paramlist=(); foreach my $key (keys(%Apache::lonnet::packagetab)) { if ($key =~ /^\Q$tag\E/) { @@ -839,8 +848,8 @@ sub answer_header { if ($Apache::lonhomework::type eq 'exam') { $bit = ($Apache::lonxml::counter+$increment).') '; } else { - $bit .= ' Answer for Part: \verb|'. - $Apache::inputtags::part.'| '; + $bit .= ' '.&mt('Answer for Part: [_1]', + '\verb|'.$Apache::inputtags::part.'|').' '; } push(@answer_bits,$bit); } else { @@ -876,7 +885,7 @@ sub answer_part { if ($env{'form.answer_output_mode'} eq 'tex') { if (!$args->{'no_verbatim'}) { my $to_use='|'; - foreach my $value (32..126) { + foreach my $value (33..41,43..126) { my $char=pack('c',$value); if ($answer !~ /\Q$char\E/) { $to_use=$char; @@ -928,7 +937,7 @@ sub answer_footer { sub showallfoils { if (defined($env{'form.showallfoils'})) { my ($symb)=&Apache::lonnet::whichuser(); - if (($env{'request.state'} eq 'construct') || + if (($env{'request.state'} eq 'construct') || ($env{'user.adv'} && $symb eq '') || ($Apache::lonhomework::viewgrades) ) { return 1; @@ -962,7 +971,7 @@ Optional Arguments: 'A is 1' -> a number between 1 and 26 'letter' -> a letter between 'A' and 'Z' $lines - undef problem only needs a single line of bubbles. - nonzero Problem wants the first nonempty response in + nonzero Problem wants the first nonempty response in $lines lines of bubbles. $bubbles_per_line - Must be provided if lines is defined.. number of bubbles on a line. @@ -1000,7 +1009,6 @@ sub getresponse { if ((defined($response)) && ($response ne "") && ($response ne " ")) { last; } - } # save bubbled letter for later @@ -1026,7 +1034,7 @@ sub getresponse { } else { $response = $env{$formparm}; } - # + # # If we have a nonempty answer, correct the numeric value # of the answer for the line on which it was found. # @@ -1041,13 +1049,13 @@ sub getresponse { In scalar context: returns: the number of lines that are required to encode the weight. -(Default is for 10 bubbles per bubblesheet item; other (integer) -values can be specified by using a custom Bubblesheet format file -with an eighteenth entry (BubblesPerRow) set to the integer +(Default is for 10 bubbles per bubblesheet item; other (integer) +values can be specified by using a custom Bubblesheet format file +with an eighteenth entry (BubblesPerRow) set to the integer appropriate for the bubblesheets which will be used to assign weights. In array context: - + returns: number of lines required to encode weight, and bubbles/line. =cut @@ -1057,19 +1065,19 @@ sub repetition { my $weight = &Apache::lonnet::EXT("resource.$id.weight"); if (!defined($weight) || ($weight eq '')) { $weight=1; } my $bubbles_per_row; - if (($env{'form.bubbles_per_row'} =~ /^\d+$/) && + if (($env{'form.bubbles_per_row'} =~ /^\d+$/) && ($env{'form.bubbles_per_row'} > 0)) { $bubbles_per_row = $env{'form.bubbles_per_row'}; } else { $bubbles_per_row = 10; } my $denominator = $bubbles_per_row; - if (($env{'form.scantron_lastbubblepoints'} == 0) && + if (($env{'form.scantron_lastbubblepoints'} == 0) && ($bubbles_per_row > 1)) { $denominator = $bubbles_per_row - 1; - } + } my $repetition = int($weight/$denominator); - if ($weight % $denominator != 0) { $repetition++; } + if ($weight % $denominator != 0) { $repetition++; } if (wantarray) { return ($repetition,$bubbles_per_row); } @@ -1097,7 +1105,7 @@ Arguments $part_id - id of the part to grade $response_id - id of the response to grade - + =cut @@ -1135,8 +1143,11 @@ sub scored_response { sub whichorder { my ($max,$randomize,$showall,$hash,$rndseed)=@_; #&Apache::lonxml::debug("man $max randomize $randomize"); - if (!defined(@{ $$hash{'names'} })) { return; } - my @names = @{ $$hash{'names'} }; + my @names; + if (ref($hash->{'names'}) eq 'ARRAY') { + @names = @{$hash->{'names'}}; + } + return if (!@names); my @whichopt =(); my (%top,@toplist,%bottom,@bottomlist); if (!($showall || ($randomize eq 'no'))) { @@ -1192,9 +1203,9 @@ sub show_answer { if (($Apache::lonhomework::history{"resource.$part.awarded"} >= 1) || (&Apache::lonnet::EXT("resource.$part.retrypartial") !~/^1|on|yes$/)) { $canshow = 1; - } + } } - return (($canshow && &Apache::lonhomework::show_problem_status()) + return (($canshow && &Apache::lonhomework::show_problem_status()) || $status eq "SHOW_ANSWER"); } @@ -1223,8 +1234,11 @@ sub check_if_computed { sub pick_foil_for_concept { my ($target,$attrs,$hinthash,$parstack,$safeeval)=@_; - if (not defined(@{ $Apache::response::conceptgroup{'names'} })) { return; } - my @names = @{ $Apache::response::conceptgroup{'names'} }; + my @names; + if (ref($Apache::response::conceptgroup{'names'}) eq 'ARRAY') { + @names = @{ $Apache::response::conceptgroup{'names'} }; + } + return if (!@names); my $pick=int(&Math::Random::random_uniform() * ($#names+1)); my $name=$names[$pick]; push @{ $Apache::response::foilgroup{'names'} }, $name; @@ -1262,7 +1276,7 @@ sub pick_foil_for_concept { Get a parameter associated with a problem. Parameters: - $id - the id of the paramater, either a part id, + $id - the id of the paramater, either a part id, or a partid and responspe id joined by _ $name - Name of the parameter to fetch $default - Default value for the paramter. @@ -1286,7 +1300,7 @@ sub get_response_param { sub submitted { my ($who)=@_; - + # when scatron grading any submission is a submission if ($env{'form.submitted'} eq 'scantron') { return 1; } # if the caller only cared if this was a scantron submission @@ -1301,7 +1315,7 @@ sub submitted { return 1; } # Submit All button on a .page was pressed - if (defined($env{'form.all_submit'})) { return 1; } + if ($env{'form.all_submit'}) { return 1; } # otherwise no submission occurred return 0; } @@ -1329,7 +1343,7 @@ sub add_to_gradingqueue { } } -=pod +=pod =item check_status() @@ -1337,10 +1351,12 @@ basically undef and 0 (both false) mean and all true values mean that they can't do any more work a return of undef means it is unattempted - a return of 0 means it is attmpted and wrong but still has tries + a return of 0 means it is both attempted and still has tries and + is wrong or is only partially correct, and retries + are allowed. a return of 1 means it is marked correct - a return of 2 means they have exceed maximum number of tries - a return of 3 means it after the answer date + a return of 2 means they have exceeded maximum number of tries + a return of 3 means it is after the answer date =cut @@ -1349,7 +1365,7 @@ sub check_status { if (!defined($id)) { $id=$Apache::inputtags::part; } my $curtime=&Apache::lonnet::EXT('system.time'); my $opendate=&Apache::lonnet::EXT("resource.$id.opendate"); - my $duedate=&Apache::lonnet::EXT("resource.$id.duedate"); + my $duedate=&Apache::lonhomework::due_date($id); my $answerdate=&Apache::lonnet::EXT("resource.$id.answerdate"); if ( $opendate && $curtime > $opendate && $duedate && $curtime > $duedate && @@ -1357,7 +1373,13 @@ sub check_status { return 3; } my $status=&Apache::lonnet::EXT("user.resource.resource.$id.solved"); - if ($status =~ /^correct/) { return 1; } + if ($status =~ /^correct/) { + my $awarded=&Apache::lonnet::EXT("user.resource.resource.$id.awarded"); + my $retrypartial=&Apache::lonnet::EXT("resource.$id.retrypartial"); + unless (($retrypartial =~ /^1|on|yes$/) && ($awarded <1)) { + return 1; + } + } if (!$status) { return undef; } my $maxtries=&Apache::lonnet::EXT("resource.$id.maxtries"); if ($maxtries eq '') { $maxtries=2; } @@ -1405,7 +1427,7 @@ sub setup_prior_tries_hash { } } } - if ($questiontype eq 'randomizetry') { + if ($questiontype eq 'randomizetry') { my $order_key = "$partprefix.$id.foilorder"; my @whichopts = &Apache::lonnet::str2array($Apache::lonhomework::history{$order_key}); if (@whichopts > 0) { @@ -1425,7 +1447,7 @@ sub setup_prior_tries_hash { 1; __END__ - + =pod =cut