--- loncom/homework/structuretags.pm 2017/12/22 01:55:28 1.557 +++ loncom/homework/structuretags.pm 2023/09/10 18:12:53 1.578 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # definition of tags that give a structure to a document # -# $Id: structuretags.pm,v 1.557 2017/12/22 01:55:28 raeburn Exp $ +# $Id: structuretags.pm,v 1.578 2023/09/10 18:12:53 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -62,7 +62,9 @@ use Apache::lonxml; use Apache::londefdef; use Apache::lonenc(); use Apache::loncommon(); +use Apache::lonnavmaps; use Time::HiRes qw( gettimeofday tv_interval ); +use HTML::Entities(); use lib '/home/httpd/lib/perl/'; use LONCAPA; @@ -341,7 +343,7 @@ var keypresshandled = 0; var postsubmit = '$postsubmit'; \$(document).ready(function(){ - if (postsubmit != 'off') { + if (postsubmit != 'off') { \$(document).keypress(function(event){ var keycode = (event.keyCode ? event.keyCode : event.which); if ((keycode == '13') && (keypresshandled == 0)) { @@ -366,12 +368,12 @@ var postsubmit = '$postsubmit'; submithandled = 1; \$( "#msg_"+buttonId ).css({"display": "inline","background-color": "#87cefa", "color": "black","padding": "2px"}) ; - if (( \$(this.form).id == "LC_page" ) && (\$('input[name="all_submit"]').length )) { + if (( \$(this.form).attr("id") == "LC_page" ) && (\$('input[name="all_submit"]').length )) { if (buttonId != "all_submit") { \$( ".LC_status_"+buttonId ).hide(); - if (( "#"+buttonId+"_pressed" ).length) { - \$( "#"+buttonId+"_pressed" ).val( "1" ); - } + } + if (( "#"+buttonId+"_pressed" ).length) { + \$( "#"+buttonId+"_pressed" ).val( "1" ); } } else { \$( ".LC_status_"+buttonId ).hide(); @@ -384,11 +386,9 @@ var postsubmit = '$postsubmit'; if (timeout > 0) { setTimeout(function(){ \$( "#msg_"+buttonId ).css({"display": "none"}); - if (( \$(this.form).id == "LC_page" ) && (\$('input[name="all_submit"]').length )) { - if (buttonId != "all_submit") { - if (( "#"+buttonId+"_pressed" ).length) { - \$( "#"+buttonId+"_pressed" ).val( "" ); - } + if (( \$(this.form).attr("id") == "LC_page" ) && (\$('input[name="all_submit"]').length )) { + if (( "#"+buttonId+"_pressed" ).length) { + \$( "#"+buttonId+"_pressed" ).val( "" ); } } \$( ".LC_hwk_submit" ).prop( "disabled", false); @@ -554,11 +554,20 @@ sub page_start { && $env{'request.state'} eq 'construct') { if ($target eq 'web' || $target eq 'edit') { unless ($env{'form.inhibitmenu'} eq 'yes') { + my $text = 'Authoring Space'; + my $href = &Apache::loncommon::authorspace($env{'request.uri'}); + if ($env{'request.course.id'}) { + my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + if ($href eq "/priv/$cdom/$cnum/") { + $text = &mt('Course Authoring Space'); + } + } # Breadcrumbs for Authoring Space &Apache::lonhtmlcommon::clear_breadcrumbs(); &Apache::lonhtmlcommon::add_breadcrumb({ - 'text' => 'Authoring Space', - 'href' => &Apache::loncommon::authorspace($env{'request.uri'}), + 'text' => $text, + 'href' => $href, }); # breadcrumbs (and tools) will be created # in start_page->bodytag->innerregister @@ -626,7 +635,9 @@ sub page_start { my ($symb,$courseid,$udom,$uname)=&Apache::lonnet::whichuser(); my ($path,$multiresp) = &Apache::loncommon::get_turnedin_filepath($symb,$uname,$udom); - if (($is_task) || ($needs_upload)) { + if ($env{'request.user_in_effect'}) { + $form_tag_start .= ' onsubmit="preventDefault();"'; + } elsif (($is_task) || ($needs_upload)) { $form_tag_start .= ' onsubmit="return file_submission_check(this,'."'$path','$multiresp'".');"'; } $form_tag_start.='>'."\n"; @@ -669,15 +680,40 @@ sub get_resource_name { } sub setup_rndseed { - my ($safeeval,$target,$probpartlist)=@_; + my ($safeeval,$target,$probpartlist,$prevparttype)=@_; my ($symb)=&Apache::lonnet::whichuser(); - my ($questiontype,$set_safespace,$rndseed); + my ($questiontype,$set_safespace,$rndseed,$numtries,$reqtries); if ($target eq 'analyze') { $questiontype = $env{'form.grade_questiontype'}; } unless (defined($questiontype)) { $questiontype = $Apache::lonhomework::type; } + if ($Apache::lonhomework::type eq 'randomizetry') { + my $partfortries = $Apache::inputtags::part; +# +# Where question type is "randomizetry" for a problem containing +# a single part (and unless type is explicitly set to not be +# "randomizetry" for that part), the number of tries used to +# determine randomization will be for that part, and randomization +# from calls to &random() in a perl script block before the part tag, +# will change based on the number of tries, and value of the +# "randomizeontries" parameter in effect for the single part. +# + if (ref($probpartlist) eq 'ARRAY') { + if ((@{$probpartlist} == 1) && ($probpartlist->[0] ne $partfortries)) { + if (&Apache::lonnet::EXT('resource.'.$probpartlist->[0].'.type') eq 'randomizetry') { + $partfortries = $probpartlist->[0]; + } else { + $partfortries = ''; + } + } + } + if ($partfortries ne '') { + $numtries = $Apache::lonhomework::history{"resource.$partfortries.tries"}; + $reqtries = &Apache::lonnet::EXT("resource.$partfortries.randomizeontries"); + } + } if (($env{'request.state'} eq "construct") || ($symb eq '') || ($Apache::lonhomework::type eq 'practice') @@ -695,11 +731,15 @@ sub setup_rndseed { $env{'form.rndseed'}=$rndseed; } } - if (($env{'request.state'} eq "construct") && + if ((($env{'request.state'} eq "construct") || ($symb eq '')) && ($Apache::lonhomework::type eq 'randomizetry')) { - my $tries = $Apache::lonhomework::history{"resource.$Apache::inputtags::part.tries"}; - if ($tries) { - $rndseed += $tries; + if ($numtries) { + if (($reqtries =~ /^\d+$/) && ($reqtries > 1)) { + my $inc = int($numtries/$reqtries); + $rndseed += $inc; + } else { + $rndseed += $numtries; + } } $env{'form.'.$Apache::inputtags::part.'.rndseed'}=$rndseed; } @@ -737,13 +777,7 @@ sub setup_rndseed { } unless (($target eq 'analyze') && (defined($rndseed))) { $rndseed=&Apache::lonnet::rndseed(); - my $partfortries = $Apache::inputtags::part; - if (ref($probpartlist) eq 'ARRAY') { - if ((@{$probpartlist} == 1) && ($probpartlist->[0] ne $Apache::inputtags::part)) { - $partfortries = $probpartlist->[0]; - } - } - my $curr_try = $Apache::lonhomework::history{"resource.$partfortries.tries"}; + my $curr_try = $numtries; if ($Apache::inputtags::status[-1] eq 'CAN_ANSWER') { $curr_try ++; } @@ -751,7 +785,6 @@ sub setup_rndseed { $rndseed = $1; } if ($curr_try) { - my $reqtries = &Apache::lonnet::EXT("resource.$partfortries.randomizeontries"); if (($reqtries =~ /^\d+$/) && ($reqtries > 1)) { my $inc = int(($curr_try-1)/$reqtries); $rndseed += $inc; @@ -764,11 +797,20 @@ sub setup_rndseed { if ($target eq 'grade') { $Apache::lonhomework::rawrndseed = $rndseed; } + } elsif ($prevparttype eq 'randomizetry') { + if ($env{'form.0.rndseed'} ne '') { + $set_safespace = 1; + $rndseed = $env{'form.0.rndseed'}; + } } if ($set_safespace) { if ($safeeval) { &Apache::lonxml::debug("Setting rndseed to $rndseed"); &Apache::run::run('$external::randomseed="'.$rndseed.'";',$safeeval); + if (($Apache::lonhomework::type eq 'randomizetry') || ($prevparttype eq 'randomizetry')) { + &Apache::lonxml::debug("Setting randomizetrypart to $Apache::inputtags::part"); + &Apache::run::run('$external::randomizetrypart="'.$Apache::inputtags::part.'";',$safeeval); + } } } unless (($env{'request.state'} eq "construct") || ($symb eq '')) { @@ -1059,7 +1101,7 @@ sub initialize_storage { } %Apache::lonhomework::history= &Apache::lonnet::tmprestore($namespace,'',$domain,$name); - my ($temp)=keys(%Apache::lonhomework::history) ; + my ($temp)=keys(%Apache::lonhomework::history); &Apache::lonxml::debug("Return message of $temp"); } else { %Apache::lonhomework::history= @@ -1082,13 +1124,13 @@ sub initialize_storage { &check_correctness_changes() is called in two circumstances in which the results hash is to be stored permanently, for grading triggered by a student's submission, where feedback on - correctness is to be provided to the student. + correctness is to be provided to the student. 1. Immediately prior to storing the results hash - To handle the case where a student's submission (and award) were + To handle the case where a student's submission (and award) were stored after history was retrieved in &initialize_storage(), e.g., - if a student submitted answers in quick succession (e.g., from + if a student submitted answers in quick succession (e.g., from multiple tabs). &Apache::inputtags::hidealldata() is called for any parts with out-of-order storage (i.e., correct then incorrect, where awarded >= 1 when correct). @@ -1098,12 +1140,12 @@ sub initialize_storage { To handle the case where lond on the student's homeserver returns delay:N -- where N is the number of transactions between the last retrieved in &initialize_storage() and the last stored immediately - before permanent storage of the current transaction via - lond::store_handler(). &Apache::grades::makehidden() is called + before permanent storage of the current transaction via + lond::store_handler(). &Apache::grades::makehidden() is called for any parts with out-of-order storage (i.e., correct then incorrect, where awarded >= 1 when correct). - Will call &store_aggregates() to increment totals for attempts, + Will call &store_aggregates() to increment totals for attempts, students, and corrects, if running user has student role. =cut @@ -1117,6 +1159,8 @@ sub finalize_storage { delete(@Apache::lonhomework::results{@remove}); my ($symb,$courseid,$domain,$name) = &Apache::lonnet::whichuser($given_symb); + my ($passback,$pbscope,$pbmap,$pbsymb,$pbtype,$crsdef,$ltinum, + $ltiref,$total,$possible,$dopassback); if ($env{'request.state'} eq 'construct' || $symb eq '' || $Apache::lonhomework::type eq 'practice') { @@ -1126,17 +1170,28 @@ sub finalize_storage { $namespace,'',$domain,$name); &Apache::lonxml::debug('Construct Store return message:'.$result); } else { - my ($laststore,$checkedparts,@parts,%postcorrect); + my ($laststore,$checkedparts,@parts,%postcorrect,%record); if (($env{'user.name'} eq $name) && ($env{'user.domain'} eq $domain) && (!$Apache::lonhomework::scantronmode) && (!defined($env{'form.grade_symb'})) && (!defined($env{'form.grade_courseid'}))) { + if (($env{'request.lti.login'}) || ($env{'request.deeplink.login'})) { + my ($map)=&Apache::lonnet::decode_symb($symb); + $map = &Apache::lonnet::clutter($map); + if ($env{'request.lti.login'}) { + ($passback,$pbscope,$pbmap,$pbsymb,$ltinum,$ltiref) = + &needs_lti_passback($courseid,$symb,$map); + } elsif ($env{'request.deeplink.login'}) { + ($passback,$pbscope,$pbmap,$pbsymb,$crsdef,$ltinum,$ltiref) = + &needs_linkprot_passback($courseid,$symb,$map); + } + } if ($Apache::lonhomework::history{'version'}) { $laststore = $Apache::lonhomework::history{'version'}.'='. $Apache::lonhomework::history{'timestamp'}; } else { $laststore = '0=0'; } - my %record = &Apache::lonnet::restore($symb,$courseid,$domain,$name); + %record = &Apache::lonnet::restore($symb,$courseid,$domain,$name); if ($record{'version'}) { my ($newversion,$oldversion,$oldtimestamp); if ($Apache::lonhomework::history{'version'}) { @@ -1212,8 +1267,98 @@ sub finalize_storage { } } } + if ($passback) { + foreach my $key (keys(%Apache::lonhomework::results)) { + if ($key =~ /^resource\.([^\.]+)\.solved$/) { + my $part = $1; + if ((($Apache::lonhomework::results{$key} =~ /^correct_/) || + ($Apache::lonhomework::results{$key} eq 'incorrect_attempted')) && + ($Apache::lonhomework::results{"resource.$part.tries"})) { + $dopassback = 1; + last; + } + } + } + } + if (($dopassback) && ($pbscope eq 'resource') && ($pbsymb eq $symb)) { + $total = 0; + $possible = 0; + my $navmap = Apache::lonnavmaps::navmap->new(); + if (ref($navmap)) { + my $res = $navmap->getBySymb($symb); + if (ref($res)) { + my $partlist = $res->parts(); + if (ref($partlist) eq 'ARRAY') { + foreach my $part (@{$partlist}) { + unless (exists($Apache::lonhomework::results{"resource.$part.solved"})) { + next if ($Apache::lonhomework::record{"resource.$part.solved"} =~/^excused/); + my $weight = &Apache::lonnet::EXT("resource.$part.weight",$symb); + $possible += $weight; + if (($record{'version'}) && (exists($record{"resource.$part.awarded"}))) { + my $awarded = $record{"resource.$part.awarded"}; + if ($awarded) { + $total += $weight * $awarded; + } + } + } + } + } + } + } + foreach my $key (keys(%Apache::lonhomework::results)) { + if ($key =~ /^resource\.([^\.]+)\.awarded$/) { + my $part = $1; + my $weight = &Apache::lonnet::EXT("resource.$part.weight",$symb); + $possible += $weight; + my $awarded = $Apache::lonhomework::results{$key}; + if ($awarded) { + $total += $weight * $awarded; + } + } + } + } &Apache::lonxml::debug('Store return message:'.$result); &store_aggregates($symb,$courseid); + if ($dopassback) { + my $scoreformat = 'decimal'; + if (($env{'request.lti.login'}) || ($env{'request.deeplink.login'})) { + if (ref($ltiref) eq 'HASH') { + if ($ltiref->{'scoreformat'} =~ /^(decimal|ratio|percentage)$/) { + $scoreformat = $1; + } + } + } + my ($pbid,$pburl,$pbtype); + if ($env{'request.lti.login'}) { + $pbid = $env{'request.lti.passbackid'}; + $pburl = $env{'request.lti.passbackurl'}; + $pbtype = 'lti'; + } elsif ($env{'request.deeplink.login'}) { + $pbid = $env{'request.linkprotpbid'}; + $pburl = $env{'request.linkprotpburl'}; + $pbtype = 'linkprot'; + } + my $ltigrade = { + 'ltinum' => $ltinum, + 'lti' => $ltiref, + 'crsdef' => $crsdef, + 'cid' => $courseid, + 'uname' => $env{'user.name'}, + 'udom' => $env{'user.domain'}, + 'pbid' => $pbid, + 'pburl' => $pburl, + 'pbtype' => $pbtype, + 'scope' => $pbscope, + 'pbmap' => $pbmap, + 'pbsymb' => $pbsymb, + 'format' => $scoreformat, + }; + if ($pbscope eq 'resource') { + $ltigrade->{'total'} = $total; + $ltigrade->{'possible'} = $possible; + } + push(@Apache::lonhomework::ltipassback,$ltigrade); + } } } else { &Apache::lonxml::debug('Nothing to store'); @@ -1221,18 +1366,106 @@ sub finalize_storage { return $result; } +sub needs_lti_passback { + my ($courseid,$symb,$map) = @_; + if (($env{'request.lti.passbackid'}) && ($env{'request.lti.passbackurl'})) { + if ($courseid =~ /^($LONCAPA::match_domain)_($LONCAPA::match_courseid)$/) { + my ($cdom,$cnum) = ($1,$2); + my %lti = &Apache::lonnet::get_domain_lti($cdom,'provider'); + if (ref($lti{$env{'request.lti.login'}}) eq 'HASH') { + if ($lti{$env{'request.lti.login'}}{'passback'}) { + my $itemnum = $env{'request.lti.login'}; + my ($ltiscope,$ltiuri,$ltisymb) = + &LONCAPA::ltiutils::lti_provider_scope($env{'request.lti.uri'}, + $cdom,$cnum,1); + my ($passback,$ltimap); + if ($ltiscope eq 'resource') { + if ($ltisymb eq $symb) { + $passback = 1; + } + } elsif ($ltiscope eq 'map') { + if ($ltiuri eq $map) { + $passback = 1; + $ltimap = $map; + } + } elsif ($ltiscope eq 'course') { + if (($env{'request.lti.uri'} eq "/$cdom/$cnum") || ($env{'request.lti.uri'} eq '')) { + $passback = 1; + } + } + return ($passback,$ltiscope,$ltimap,$ltisymb,$itemnum,$lti{$itemnum}); + } + } + } + } + return; +} + +sub needs_linkprot_passback { + my ($courseid,$symb,$map) = @_; + if (($env{'request.linkprotpbid'}) && ($env{'request.linkprotpburl'})) { + if ($courseid =~ /^($LONCAPA::match_domain)_($LONCAPA::match_courseid)$/) { + my ($cdom,$cnum) = ($1,$2); + my ($deeplink_symb,$deeplink_map,$deeplink,$passback); + $deeplink_symb = &Apache::loncommon::deeplink_login_symb($cnum,$cdom); + if ($deeplink_symb) { + if ($deeplink_symb =~ /\.(page|sequence)$/) { + $deeplink_map = &Apache::lonnet::deversion((&Apache::lonnet::decode_symb($deeplink_symb))[2]); + my $navmap = Apache::lonnavmaps::navmap->new(); + if (ref($navmap)) { + $deeplink = $navmap->get_mapparam(undef,$deeplink_map,'0.deeplink'); + } + } else { + $deeplink = &Apache::lonnet::EXT('resource.0.deeplink',$deeplink_symb); + $deeplink_map = &Apache::lonnet::deversion((&Apache::lonnet::decode_symb($deeplink_symb))[0]); + } + if (($deeplink ne '') && ($env{'request.linkprot'} ne '')) { + my ($itemid,$tinyurl) = split(/:/,$env{'request.linkprot'}); + if ($itemid =~ /^(\d+)(c|d)$/) { + my ($itemnum,$itemtype) = ($1,$2); + my ($crsdef,$lti_in_use); + if ($itemtype eq 'c') { + $crsdef = 1; + my %crslti = &Apache::lonnet::get_course_lti($cnum,$cdom,'provider'); + $lti_in_use = $crslti{$itemnum}; + } else { + my %domlti = &Apache::lonnet::get_domain_lti($cdom,'linkprot'); + $lti_in_use = $domlti{$itemnum}; + } + my ($state,$others,$listed,$scope,$protect,$display,$target,$exit) = split(/,/,$deeplink); + my $passback; + if ($scope eq 'resource') { + if ($deeplink_symb eq $symb) { + $passback = 1; + } + } elsif ($scope eq 'map') { + if (&Apache::lonnet::clutter($deeplink_map) eq $map) { + $passback = 1; + } + } elsif ($scope eq 'recurse') { +#FIXME check if $deeplink_map contains $map + $passback = 1; + } + return ($passback,$scope,$deeplink_map,$deeplink_symb,$crsdef,$itemnum,$lti_in_use); + } + } + } + } + } +} + =pod =item check_correctness_changes() For all parts for which current results contain a solved status - of "incorrect_attempted", check if there was a transaction in which - solved was set to "correct_by_student" in the time since the last - transaction (retrieved when &initialize_storage() was called i.e., + of "incorrect_attempted", check if there was a transaction in which + solved was set to "correct_by_student" in the time since the last + transaction (retrieved when &initialize_storage() was called i.e., when &start_problem() was called), unless: (a) questiontype parameter is set to survey or anonymous survey (+/- credit) (b) problemstatus is set to no or no_feedback_ever - If such a transaction exists, and did not occur after "reset status" + If such a transaction exists, and did not occur after "reset status" by a user with grading privileges, then the current transaction is an example of an out-of-order transaction (i.e., incorrect occurring after correct). Accordingly, the current transaction should be hidden. @@ -1501,9 +1734,11 @@ sub firstaccess_msg { my $uri = &Apache::lonenc::check_encrypt($env{'request.uri'}); my $buttontext = &mt('Show Resource'); my $timertext = &mt('Start Timer?'); + my $shownsymb = &HTML::Entities::encode(&Apache::lonenc::check_encrypt($symb),'\'"<>&'); $result .= (< + ENDCHECKOUT @@ -1545,6 +1780,7 @@ sub init_problem_globals { @Apache::structuretags::whilebody=(); @Apache::structuretags::whileline=(); $Apache::lonhomework::scantronmode=0; + $Apache::lonhomework::randomizetrypart=0; undef($Apache::lonhomework::name); undef($Apache::lonhomework::default_type); undef($Apache::lonhomework::type); @@ -1568,6 +1804,7 @@ sub reset_problem_globals { undef($Apache::lonhomework::default_type); undef($Apache::lonhomework::type); undef($Apache::lonhomework::scantronmode); + undef($Apache::inputtags::randomizetrypart); undef($Apache::lonhomework::ignore_response_errors); undef(@Apache::functionplotresponse::callscripts); &Apache::lonhomework::reset_show_problem_status(); @@ -1662,14 +1899,17 @@ sub start_problem { my $ipused; my $name= &get_resource_name($parstack,$safeeval); - my ($result,$form_tag_start,$slot_name,$slot,$probpartlist); + my ($result,$form_tag_start,$slot_name,$slot,$probpartlist,$firstaccres); if ($target eq 'web' || $target eq 'grade' || $target eq 'answer' || $target eq 'tex') { if ($env{'form.markaccess'}) { my @interval=&Apache::lonnet::EXT("resource.0.interval"); my ($timelimit) = split(/_/,$interval[0]); - &Apache::lonnet::set_first_access($interval[1],$timelimit); + my $is_set = &Apache::lonnet::set_first_access($interval[1],$timelimit); + unless (($is_set eq 'ok') || ($is_set eq 'already_set')) { + $firstaccres = $is_set; + } } } @@ -1681,15 +1921,22 @@ sub start_problem { } elsif ((($target eq 'grade') && ($Apache::lonhomework::type eq 'randomizetry')) || ($target eq 'answer')) { my ($symb)= &Apache::lonnet::whichuser(); - my $navmap = Apache::lonnavmaps::navmap->new(); - if (ref($navmap)) { - my $res = $navmap->getBySymb($symb); - if (ref($res)) { - $probpartlist = $res->parts(); + if ($symb ne '') { + my $navmap = Apache::lonnavmaps::navmap->new(); + if (ref($navmap)) { + my $res = $navmap->getBySymb($symb); + if (ref($res)) { + $probpartlist = $res->parts(); + } } } } + if (($target eq 'web') && ($env{'request.user_in_effect'})) { + &Apache::lonxml::get_all_text("/problem",$parser,$style); + return $result; + } + if ($target eq 'web' || $target eq 'grade' || $target eq 'answer' || $target eq 'tex') { @@ -1705,7 +1952,14 @@ sub start_problem { if ($target eq 'web' || $target eq 'grade' || $target eq 'answer' || $target eq 'tex') { + my ($symb) = &Apache::lonnet::whichuser(); #handle rand seed in construction space + if (($env{'request.state'} eq 'construct') || ($symb eq '')) { + my $partorder=&Apache::lonnet::metadata($env{'request.uri'},'partorder'); + if ($partorder ne '') { + @{$probpartlist} = split(/,/,$partorder); + } + } my $rndseed=&setup_rndseed($safeeval,$target,$probpartlist); if (($target eq 'grade') && &Apache::response::submitted()) { if ($Apache::lonhomework::type eq 'randomizetry') { @@ -1720,12 +1974,15 @@ sub start_problem { } } } - my ($symb)=&Apache::lonnet::whichuser(); if ($env{'request.state'} ne "construct" && ($symb eq '' || $Apache::lonhomework::type eq 'practice')) { + my $rndseedval = $rndseed; + if (($symb eq '') && ($Apache::lonhomework::type eq 'randomizetry')) { + $rndseedval = $env{'form.rndseed'}; + } $form_tag_start.=''. + $rndseedval.'" />'. ''; if (exists($env{'form.username'})) { @@ -1747,15 +2004,22 @@ sub start_problem { $form_tag_start.=&practice_problem_header(); } $form_tag_start.='
'; - } elsif (($env{'request.state'} ne "construct") && - ($Apache::lonhomework::type eq 'randomizetry') && - ($status eq 'CAN_ANSWER') && - ($env{'course.'.$env{'request.course.id'}.'.type'} ne 'Placement') && - (!$env{'request.role.adv'})) { + } + if (($env{'request.state'} ne "construct") && + ($Apache::lonhomework::type eq 'randomizetry') && + ($status eq 'CAN_ANSWER') && + ($env{'course.'.$env{'request.course.id'}.'.type'} ne 'Placement') && + (!$env{'request.role.adv'})) { # "New Problem Variation Each Try" header suppressed for Placement Tests, unless course personnel. - my $reqtries = &Apache::lonnet::EXT("resource.$Apache::inputtags::part.randomizeontries"); - my $problemstatus = &get_problem_status($Apache::inputtags::part); - $form_tag_start.=&randomizetry_problem_header($problemstatus,$reqtries); + my @parts; + if (ref($probpartlist) eq 'ARRAY') { + @parts = @{$probpartlist}; + } + unless (@parts) { + my $reqtries = &Apache::lonnet::EXT("resource.$Apache::inputtags::part.randomizeontries"); + my $problemstatus = &get_problem_status($Apache::inputtags::part); + $form_tag_start.=&randomizetry_problem_header($problemstatus,$reqtries,$symb); + } } my $expression='$external::datestatus="'.$status.'";'; @@ -1776,6 +2040,10 @@ sub start_problem { ( $status eq 'NEED_DIFFERENT_IP')) { my $bodytext=&Apache::lonxml::get_all_text("/problem",$parser, $style); + if (($status eq 'NOT_YET_VIEWED') && ($firstaccres)) { + $result .= '

'. + &mt('A problem occurred when trying to start the timer.').'

'; + } $result .= &access_status_msg('problem',$status,$symb,$target,$ipused,$accessmsg); } elsif ($status eq 'NEEDS_CHECKIN') { my $bodytext=&Apache::lonxml::get_all_text("/problem",$parser, @@ -1809,6 +2077,10 @@ sub start_problem { $result.= ''. &practice_problem_header().'
'; + } elsif ($Apache::lonhomework::type eq 'randomizetry') { + my $reqtries = &Apache::lonnet::EXT("resource.$Apache::inputtags::part.randomizeontries"); + my $problemstatus = &get_problem_status($Apache::inputtags::part); + $result.=&randomizetry_problem_header($problemstatus,$reqtries); } } # if we are viewing someone else preserve that info @@ -1949,6 +2221,12 @@ sub end_problem { } } $result =~ s/INSERTTEXFRONTMATTERHERE/$frontmatter/; + } elsif ($target eq 'web') { + if ($env{'request.user_in_effect'}) { + &reset_problem_globals('problem'); + $result .= &Apache::lonhtmlcommon::set_compute_end_time(); + return $result; + } } my $status=$Apache::inputtags::status['-1']; @@ -2040,7 +2318,24 @@ sub end_problem { } } if ($target eq 'web') { - $result.=&Apache::functionplotresponse::init_script(); + $result.=&Apache::functionplotresponse::init_script(); + if ($Apache::lonhomework::default_type eq 'randomizetry') { + my ($symb) = &Apache::lonnet::whichuser(); + if ((($env{'request.state'} eq 'construct') || ($symb eq '')) && + ($status eq 'CAN_ANSWER')) { + unless (@Apache::inputtags::partlist > 1) { + $result.= <<"ENDJS"; + +ENDJS + } + } + } } if ($target eq 'grade') { &Apache::lonhomework::showhash(%Apache::lonhomework::results); @@ -2057,7 +2352,7 @@ sub end_problem { @Apache::inputtags::response=(); $result=&Apache::response::mandatory_part_meta; } - $result.=&Apache::response::meta_part_order(); + $result.=&Apache::response::meta_part_order('problem'); $result.=&Apache::response::meta_response_order(); } elsif ($target eq 'edit') { &Apache::lonxml::debug("in end_problem with $target, edit"); @@ -2078,7 +2373,8 @@ sub end_problem { # computation: # if ($target eq 'web') { - $result .= &Apache::lonhtmlcommon::set_compute_end_time(); + $result .= &Apache::lonhtmlcommon::dash_to_minus_js(). + &Apache::lonhtmlcommon::set_compute_end_time(); # # Closing tags delayed so any tags # not in head can appear inside body, for valid xhtml. @@ -2134,6 +2430,9 @@ sub end_library { && ($#$tagstack eq 0 && $$tagstack[0] eq 'library') && $env{'request.state'} eq "construct") { $result.=''.&Apache::loncommon::end_page({'discussion' => 1}); + } elsif ($target eq 'meta') { + $result.=&Apache::response::meta_part_order('library'); + $result.=&Apache::response::meta_response_order(); } if ( $#$tagstack eq 0 && $$tagstack[0] eq 'library') { &reset_problem_globals('library'); @@ -2762,6 +3061,14 @@ sub start_part { if (($target eq 'grade') && &Apache::response::submitted()) { $Apache::lonhomework::results{"resource.$id.rndseed"}=$rndseed; } + } elsif (@Apache::inputtags::partlist > 1) { + my $prevparttype = &Apache::lonnet::EXT("resource.$Apache::inputtags::partlist[-2].type"); + if ($prevparttype eq 'randomizetry') { + my $rndseed=&setup_rndseed($safeeval,$target,'',$prevparttype); + if (($target eq 'grade') && &Apache::response::submitted()) { + $Apache::lonhomework::results{"resource.$id.rndseed"}=$rndseed; + } + } } elsif (($target eq 'grade') && &Apache::response::submitted()) { $Apache::lonhomework::results{"resource.$id.rndseed"}=$Apache::lonhomework::rawrndseed; } @@ -2837,20 +3144,14 @@ sub start_part { } elsif ($target eq 'web') { if ($status eq 'CAN_ANSWER') { my $problemstatus = &get_problem_status($Apache::inputtags::part); - my $probrandomize = &Apache::lonnet::EXT("resource.$Apache::inputtags::partlist[0].type"); - my $probrandtries = &Apache::lonnet::EXT("resource.$Apache::inputtags::partlist[0].randomizeontries"); my $num = scalar(@Apache::inputtags::partlist)-1; - if ($probrandomize eq 'randomizetry') { - if (&Apache::lonnet::EXT("resource.$Apache::inputtags::part.type") ne 'randomizetry') { - $result .= &randomizetry_part_header($problemstatus,'none',$num); - } else { - my $reqtries = &Apache::lonnet::EXT("resource.$Apache::inputtags::part.randomizeontries"); - if ($probrandtries ne $reqtries) { - $result .= &randomizetry_part_header($problemstatus,$reqtries,$num); - } - } - } elsif (&Apache::lonnet::EXT("resource.$Apache::inputtags::part.type") eq 'randomizetry') { - my $reqtries = &Apache::lonnet::EXT("resource.$Apache::inputtags::part.randomizeontries"); + if ((($Apache::lonhomework::default_type eq 'randomizetry') || + ($Apache::lonhomework::randomizetrypart)) && + ($Apache::lonhomework::type ne 'randomizetry')) { + $result .= &randomizetry_part_header($problemstatus,'none',$num); + } elsif ($Apache::lonhomework::type eq 'randomizetry') { + $Apache::lonhomework::randomizetrypart = 1; + my $reqtries = &Apache::lonnet::EXT("resource.$id.randomizeontries"); $result .= &randomizetry_part_header($problemstatus,$reqtries,$num); } } @@ -2905,7 +3206,11 @@ sub end_part { $gradestatus=''; } $result.=$gradestatus; - if ($$tagstack[-2] eq 'td' and $target eq 'tex') {$result.='\end{minipage}';} + if ($$tagstack[-2] eq 'td' and $target eq 'tex') { + if (not $env{'form.problem_split'}=~/yes/) { + $result.='\end{minipage}'; + } + } } elsif ($target eq 'edit') { $result.=&Apache::edit::end_table(); } elsif ($target eq 'modified') { @@ -3170,7 +3475,7 @@ sub practice_problem_header { } sub randomizetry_problem_header { - my ($problemstatus,$reqtries) = @_; + my ($problemstatus,$reqtries,$symb) = @_; my ($header,$text); if ($reqtries > 1) { $header = &mt('New Problem Variation After Every [quant,_1,Try,Tries]',$reqtries); @@ -3190,8 +3495,13 @@ sub randomizetry_problem_header { $text = &mt('A new variation will be generated after each try until correct or tries limit is reached.'); } } - return '

'.$header.'

'. - ''.$text.'
'; + if (($env{'request.state'} eq "construct") || ($symb eq '')) { + return ''; + } else { + return '

'.$header.'

'. + ''.$text.'
'; + } } sub randomizetry_part_header { @@ -3199,7 +3509,7 @@ sub randomizetry_part_header { my ($header,$text); if ($reqtries eq 'none') { $header = &mt('No Question Variation'); - $text = &mt('For this question there will no new variation after a try.'); + $text = &mt('For this question there will be no new variation after a try.'); } elsif ($reqtries > 1) { $header = &mt('New Question Variation After Every [quant,_1,Try,Tries]',$reqtries); if (($problemstatus eq 'no') ||