--- loncom/homework/structuretags.pm 2024/02/27 22:23:13 1.512.2.24.2.12 +++ loncom/homework/structuretags.pm 2023/06/04 13:25:21 1.576 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # definition of tags that give a structure to a document # -# $Id: structuretags.pm,v 1.512.2.24.2.12 2024/02/27 22:23:13 raeburn Exp $ +# $Id: structuretags.pm,v 1.576 2023/06/04 13:25:21 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -69,7 +69,7 @@ use lib '/home/httpd/lib/perl/'; use LONCAPA; BEGIN { - &Apache::lonxml::register('Apache::structuretags',('block','languageblock','translated','instructorcomment','while','randomlist','problem','library','web','tex','part','preduedate','postanswerdate','solved','notsolved','problemtype','startpartmarker','startouttext','endpartmarker','endouttext','simpleeditbutton','definetag')); + &Apache::lonxml::register('Apache::structuretags',('block','languageblock','translated','instructorcomment','while','randomlist','problem','library','web','print','tex','part','preduedate','postanswerdate','solved','notsolved','problemtype','startpartmarker','startouttext','endpartmarker','endouttext','simpleeditbutton','definetag')); } @@ -194,6 +194,28 @@ sub end_web { return ''; } +sub start_print { + my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; + if ($target ne 'edit' && $target ne 'modified') { + if ($target ne 'tex') { + my $skip = &Apache::lonxml::get_all_text("/print",$parser,$style); + &Apache::lonxml::debug("skipping ahead :$skip: $$parser[-1]"); + } + } elsif ($target eq "edit") { + my $bodytext = &Apache::lonxml::get_all_text_unbalanced("/print",$parser); + my $result = &Apache::edit::tag_start($target,$token); + $result .= &Apache::edit::editfield($token->[1],$bodytext,'',80,1); + return $result; + } elsif ($target eq "modified") { + return $token->[4].&Apache::edit::modifiedfield("/print",$parser); + } + return ''; +} + +sub end_print { + return ''; +} + sub start_tex { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result=''; @@ -228,9 +250,11 @@ sub end_tex { sub homework_js { my ($postsubmit,$timeout); if (($env{'request.course.id'}) && ($env{'request.state'} ne 'construct')) { - my $crstype; - if (&Apache::loncommon::course_type() eq 'Community') { + my $crstype = &Apache::loncommon::course_type(); + if ($crstype eq 'Community') { $crstype = 'community'; + } elsif ($crstype eq 'Placement') { + $crstype = 'placement'; } else { if ($env{'course.'.$env{'request.course.id'}.'.internal.coursecode'}) { $crstype = 'official'; @@ -272,8 +296,8 @@ sub homework_js { $jstimeout = 1000 * $timeout; } return &Apache::loncommon::resize_textarea_js(). - &Apache::loncommon::colorfuleditor_js(). - &Apache::lonxml::setmode_javascript(). + &Apache::loncommon::colorfuleditor_js(). + &setmode_javascript(). <<"JS"; +ENDSCRIPT +} + sub page_start { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$name, $extra_head)=@_; @@ -481,9 +520,9 @@ sub page_start { } } if ($needs_upload) { - $extra_head .= &Apache::lonhtmlcommon::file_submissionchk_js(). - ''; + $extra_head .= &Apache::lonhtmlcommon::file_submissionchk_js() + .''; } } @@ -514,23 +553,25 @@ sub page_start { } elsif (!defined($found{'body'}) && $env{'request.state'} eq 'construct') { if ($target eq 'web' || $target eq 'edit') { - # Breadcrumbs for Authoring Space - &Apache::lonhtmlcommon::clear_breadcrumbs(); - &Apache::lonhtmlcommon::add_breadcrumb({ - 'text' => 'Authoring Space', - 'href' => &Apache::loncommon::authorspace($env{'request.uri'}), - }); - # breadcrumbs (and tools) will be created - # in start_page->bodytag->innerregister + unless ($env{'form.inhibitmenu'} eq 'yes') { + # Breadcrumbs for Authoring Space + &Apache::lonhtmlcommon::clear_breadcrumbs(); + &Apache::lonhtmlcommon::add_breadcrumb({ + 'text' => 'Authoring Space', + 'href' => &Apache::loncommon::authorspace($env{'request.uri'}), + }); + # breadcrumbs (and tools) will be created + # in start_page->bodytag->innerregister # FIXME Where are we? -# &Apache::lonhtmlcommon::add_breadcrumb({ -# 'text' => 'Problem Editing', # 'Problem Testing' -# 'href' => '', -# }); - $pageheader =&Apache::loncommon::head_subbox( - &Apache::loncommon::CSTR_pageheader()); - } +# &Apache::lonhtmlcommon::add_breadcrumb({ +# 'text' => 'Problem Editing', # 'Problem Testing' +# 'href' => '', +# }); + $pageheader = &Apache::loncommon::head_subbox( + &Apache::loncommon::CSTR_pageheader()); + } + } } elsif (!defined($found{'body'})) { my %add_entries; my $background=&Apache::lonxml::get_param('background',$parstack, @@ -630,7 +671,7 @@ 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,$numtries,$reqtries); if ($target eq 'analyze') { @@ -693,7 +734,7 @@ sub setup_rndseed { } $env{'form.'.$Apache::inputtags::part.'.rndseed'}=$rndseed; } - if ( ($env{'form.resetdata'} eq &mt('New Problem Variation') + if ( ($env{'form.resetdata'} eq 'new_problem_variation' && $env{'form.submitted'} eq 'yes') || $env{'form.newrandomization'} eq &mt('New Randomization')) { srand(time); @@ -747,11 +788,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 '')) { @@ -810,9 +860,9 @@ sub problem_edit_header {
'.&mt('Problem Editing').$mode.&Apache::loncommon::help_open_menu('Problem Editing','Problem_Editor_XML_Index',5,'Authoring').' -
'. - ''. - &problem_edit_buttons(); +
'. + ''. + &problem_edit_buttons(); $return .= '
' . &Apache::lonxml::message_location(); $return .= ' @@ -840,7 +890,6 @@ sub problem_edit_header { return $return; } - sub problem_edit_footer { my $resource = $env{'request.ambiguous'}; return '
@@ -916,7 +965,7 @@ sub problem_web_to_edit_header { ".&mt("Problem Type:")." - +
@@ -1001,6 +1051,12 @@ $show_all 'onclick="javascript:setmode(this.form,'."'edit'".')" />'; $result .= ''; + if ($env{'browser.type'} ne 'explorer' || $env{'browser.version'} > 9) { + my $uri = $env{'request.uri'}; + my $daxeurl = '/daxepage'.$uri; + $result .= ''; + } $result.='

@@ -1027,8 +1083,8 @@ sub initialize_storage { || $Apache::lonhomework::type eq 'practice') { my $namespace = $symb || $env{'request.uri'}; - if ($env{'form.resetdata'} eq &mt('Reset Submissions') || - ($env{'form.resetdata'} eq &mt('New Problem Variation') + if ($env{'form.resetdata'} eq 'reset_submissions' || + ($env{'form.resetdata'} eq 'new_problem_variation' && $env{'form.submitted'} eq 'yes') || $env{'form.newrandomization'} eq &mt('New Randomization')) { &Apache::lonnet::tmpreset($namespace,'',$domain,$name); @@ -1081,7 +1137,7 @@ sub initialize_storage { where awarded >= 1 when correct). Will call &store_aggregates() to increment totals for attempts, - students, and corrects, if running user has student role. + students, and corrects, if running user has student role. =cut @@ -1368,30 +1424,20 @@ sub needs_linkprot_passback { $lti_in_use = $domlti{$itemnum}; } my ($state,$others,$listed,$scope,$protect,$display,$target,$exit) = split(/,/,$deeplink); - my ($passback,$pbscope); - if ($scope eq 'res') { + my $passback; + if ($scope eq 'resource') { if ($deeplink_symb eq $symb) { $passback = 1; - $pbscope = 'resource'; } } elsif ($scope eq 'map') { if (&Apache::lonnet::clutter($deeplink_map) eq $map) { $passback = 1; - $pbscope = 'nonrec'; - } - } elsif ($scope eq 'rec') { - if (&Apache::lonnet::clutter($deeplink_map) eq $map) { - $passback = 1; - $pbscope = 'map'; - } else { - my @recurseup = &Apache::lonnet::get_map_hierarchy($map,$env{'request.course.id'}); - if (grep(/^\Q$deeplink_map\E$/,@recurseup)) { - $passback = 1; - $pbscope = 'map'; - } } + } elsif ($scope eq 'recurse') { +#FIXME check if $deeplink_map contains $map + $passback = 1; } - return ($passback,$pbscope,$deeplink_map,$deeplink_symb,$crsdef,$itemnum,$lti_in_use); + return ($passback,$scope,$deeplink_map,$deeplink_symb,$crsdef,$itemnum,$lti_in_use); } } } @@ -1504,8 +1550,8 @@ sub store_aggregates { } else { $anoncounter{$symb."\0".$part} = 1; } - my $needsrelease = $Apache::lonnet::needsrelease{'parameter:type:'.$Apache::lonhomework::results{'resource.'.$part.'.type'}}; - if ($needsrelease) { + my $needsrelease = $Apache::lonnet::needsrelease{'parameter:type:'.$Apache::lonhomework::results{'resource.'.$part.'.type'}.'::'}; + if ($needsrelease) { my $curr_required = $env{'course.'.$env{'request.course.id'}.'.internal.releaserequired'}; if ($curr_required eq '') { &Apache::lonnet::update_released_required($needsrelease); @@ -1565,6 +1611,13 @@ sub access_status_msg { &Apache::lonnavmaps::timeToHumanString($accessmsg,'start')); } elsif ($status eq 'NOTRESERVABLE') { $msg.=&mt('Not available to make a reservation.'); + } elsif ($status eq 'NEED_DIFFERENT_IP') { + if ($ipused) { + $msg.=&mt('You must use the same computer ([_1]) you used when you first accessed this resource using your time/place-based reservation.',"IP: $ipused"); + } else { + $msg.=&mt('Each student must use a different computer to access this resource at this time and/or place.').'
'. + &mt('Somebody else has already used this particular computer for that purpose.'); + } } $msg.='
'; } elsif ($target eq 'tex') { @@ -1574,20 +1627,17 @@ sub access_status_msg { $msg ='\noindent \vskip 1 mm '. $startminipage.'\vskip 0 mm'; if ($status eq 'UNAVAILABLE') { - $msg.=&mt('Unable to determine if this resource is open due to network problems. Please try again later.'); - } elsif ($status eq 'CLOSED' || $status eq 'INVALID_ACCESS') { - $msg.=&mt('Problem is not open to be viewed. It')." $accessmsg"; + $msg.=&mt('Unable to determine if this resource is open due to network problems. Please try again later.').'\vskip 0 mm '; } else { - $msg.=&mt('Problem is not open to be viewed.'); + $msg.=&mt('Problem is not open to be viewed. It')." $accessmsg \\vskip 0 mm "; } - $msg .= " \\vskip 0 mm "; } return $msg; } sub checkin_prompt { my ($target,$slot_name,$slot,$type) = @_; - my $result; + my $result; if ($target eq 'web') { $result = &Apache::bridgetask::proctor_validation_screen($slot); } elsif ($target eq 'grade') { @@ -1605,8 +1655,12 @@ sub selfcheckin_resource { $Apache::lonhomework::history{'resource.0.checkedin'}; if ($checked_in eq '') { # unproctored slot access, self checkin + my $needsiptied; + if (ref($slot)) { + $needsiptied = $slot->{'iptied'}; + } my $check = &Apache::bridgetask::check_in('problem',undef,undef, - $slot_name); + $slot_name,$needsiptied); if ($check =~ /^error: /) { &Apache::lonnet::logthis("Error during self-checkin of problem (symb: $symb) using slot: $slot_name"); } else { @@ -1631,8 +1685,8 @@ sub checkout_msg { 'resource'=>'The resource needs to be checked out', 'id_expln'=>'As a resource gets checked out, a unique timestamped ID is given to it, and a permanent record is left in the system.', 'warning'=>'Checking out resources is subject to course policies, and may exclude future credit even if done erroneously.', - 'checkout'=>'Check out Exam for Viewing', - 'checkout?'=>'Check out Exam?'); + 'checkout'=>'Check out Bubblesheet Exam for Viewing', + 'checkout?'=>'Check out Bubblesheet Exam?'); my $uri = &Apache::lonenc::check_encrypt($env{'request.uri'}); return (<$lt{'resource'} @@ -1833,6 +1887,7 @@ sub start_problem { my $status; my $accessmsg; my $resource_due; + my $ipused; my $name= &get_resource_name($parstack,$safeeval); my ($result,$form_tag_start,$slot_name,$slot,$probpartlist,$firstaccres); @@ -1841,7 +1896,7 @@ sub start_problem { $target eq 'tex') { if ($env{'form.markaccess'}) { my @interval=&Apache::lonnet::EXT("resource.0.interval"); - my ($timelimit) = ($interval[0] =~ /^(\d+)/); + my ($timelimit) = split(/_/,$interval[0]); my $is_set = &Apache::lonnet::set_first_access($interval[1],$timelimit); unless (($is_set eq 'ok') || ($is_set eq 'already_set')) { $firstaccres = $is_set; @@ -1877,10 +1932,10 @@ sub start_problem { $target eq 'tex') { my ($symb)= &Apache::lonnet::whichuser(); - ($status,$accessmsg,$slot_name,$slot) = + ($status,$accessmsg,$slot_name,$slot,$ipused) = &Apache::lonhomework::check_slot_access('0','problem',$symb,$probpartlist); push (@Apache::inputtags::status,$status); - } + } if ($target eq 'tex' and $env{'request.symb'} =~ m/\.page_/) {$result='';} @@ -1919,8 +1974,8 @@ sub start_problem { } $form_tag_start.=''. - ''; + ''; if (exists($env{'form.username'})) { $form_tag_start.= ''; } - $result .= &access_status_msg('problem',$status,$symb,$target,'',$accessmsg); + $result .= &access_status_msg('problem',$status,$symb,$target,$ipused,$accessmsg); } elsif ($status eq 'NEEDS_CHECKIN') { my $bodytext=&Apache::lonxml::get_all_text("/problem",$parser, $style); @@ -1999,11 +2058,16 @@ sub start_problem { ''; # create a page header and exit if ($env{'request.state'} eq "construct") { - $result.= &problem_web_to_edit_header($env{'form.rndseed'}); + if ($env{'form.inhibitmenu'} eq 'yes') { + # error messages can be useful in any case + $result.= &Apache::lonxml::message_location(); + } else { + $result.= &problem_web_to_edit_header($env{'form.rndseed'}); + } if ($Apache::lonhomework::type eq 'practice') { - $result.= ''. - &practice_problem_header().'
'; + $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); @@ -2193,7 +2257,39 @@ sub end_problem { # Added separately at end of this routine, after added # so document will be valid xhtml. # - $result.= &Apache::loncommon::end_page({'discussion' => 1, + my $showdisc = 1; + if (($env{'course.'.$env{'request.course.id'}.'.type'} eq 'Placement') && + (!$env{'request.role.adv'})) { +# For Placement Tests footer with "Post Discussion" and "Send Feedback" links is suppressed. + $showdisc = 0; + my ($symb)= &Apache::lonnet::whichuser(); + if ($symb) { + my $navmap = Apache::lonnavmaps::navmap->new(); + if (ref($navmap)) { + my $hastries = &Apache::lonplacementtest::has_tries($symb,$navmap); +# For Placement Tests test status is displayed if this is the last resource in the course +# and there are no tries left + unless ($hastries) { + if (&Apache::lonplacementtest::is_lastres($symb,$navmap)) { + my ($score,$incomplete) = + &Apache::lonplacementtest::check_completion(undef,undef,1); + if (!$incomplete) { + $result .= &Apache::lonplacementtest::showresult(1,1); + } elsif ($incomplete < 100) { + $result.= &Apache::lonplacementtest::showincomplete($incomplete,1); + } + } else { +# For Placement Tests score is displayed if test has just been completed + my ($score,$incomplete) = &Apache::lonplacementtest::check_completion(undef,undef,1); + if (!$incomplete) { + $result.= &Apache::lonplacementtest::showresult(1,1); + } + } + } + } + } + } + $result.= &Apache::loncommon::end_page({'discussion' => $showdisc, 'notbody' => 1}); } elsif ($target eq 'tex') { my $endminipage = ''; @@ -2247,7 +2343,7 @@ ENDJS @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"); @@ -2268,8 +2364,7 @@ ENDJS # computation: # if ($target eq 'web') { - $result .= &Apache::lonhtmlcommon::dash_to_minus_js(). - &Apache::lonhtmlcommon::set_compute_end_time(); + $result .= &Apache::lonhtmlcommon::set_compute_end_time(); # # Closing tags delayed so any tags # not in head can appear inside body, for valid xhtml. @@ -2308,9 +2403,9 @@ sub start_library { ''; $result.=&problem_web_to_edit_header($rndseed); if ($Apache::lonhomework::type eq 'practice') { - $result.= ''. - &practice_problem_header().'
'; + $result.= ''. + &practice_problem_header().'
'; } } return $result; @@ -2326,6 +2421,7 @@ sub end_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') { @@ -2955,6 +3051,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; } @@ -3031,8 +3135,8 @@ sub start_part { if ($status eq 'CAN_ANSWER') { my $problemstatus = &get_problem_status($Apache::inputtags::part); my $num = scalar(@Apache::inputtags::partlist)-1; - if ((($Apache::lonhomework::default_type eq 'randomizetry') || - ($Apache::lonhomework::randomizetrypart)) && + 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') { @@ -3092,7 +3196,7 @@ sub end_part { $gradestatus=''; } $result.=$gradestatus; - if ($$tagstack[-2] eq 'td' and $target eq 'tex') { + if ($$tagstack[-2] eq 'td' and $target eq 'tex') { if (not $env{'form.problem_split'}=~/yes/) { $result.='\end{minipage}'; } @@ -3212,7 +3316,7 @@ sub start_problemtype { ['hide','Hide']] ,$token); $result .=&Apache::edit::checked_arg('When used as type(s):','for', - [ ['exam','Exam/Quiz Problem'], + [ ['exam','Bubblesheet Exam/Quiz Problem'], ['survey','Survey'], ['surveycred','Survey (with credit)'], ['anonsurvey','Anonymous Survey'], @@ -3355,7 +3459,7 @@ sub end_simpleeditbutton { } sub practice_problem_header { - return '

'.&mt('Practice Problem').'

'. + return '

'.&mt('Practice Problem').'

'. ''.&mt('Submissions are not permanently recorded'). ''; } @@ -3417,7 +3521,7 @@ sub randomizetry_part_header { if ($num > 1) { $output .= '
'; } - $output .= '

'.$header.'

'. + $output .= '

'.$header.'

'. ''.$text.'

'; return $output; }