--- loncom/homework/structuretags.pm 2000/11/28 21:44:47 1.16
+++ loncom/homework/structuretags.pm 2006/04/14 21:42:05 1.345
@@ -1,177 +1,1627 @@
-# The LearningOnline Network with CAPA # \n";
+ }
+ }
+
+ if (defined($found{'body'})) {
+ $body_args{'skip_phases'}{'body'}=1;
+ } elsif (!defined($found{'body'})
+ && $env{'request.state'} eq 'construct') {
+ if ($target eq 'web' || $target eq 'edit') {
+ # no extra args to bodytag
+ }
+ } elsif (!defined($found{'body'})) {
+ my %add_entries;
+ my $background=&Apache::lonxml::get_param('background',$parstack,
+ $safeeval);
+ if ($background ne '' ) {
+ $add_entries{'background'} = $background;
+ }
+
+ my $bgcolor=&Apache::lonxml::get_param('bgcolor',$parstack,
+ $safeeval);
+ if ($bgcolor eq '' ) { $bgcolor = '#FFFFFF'; }
+
+ $body_args{'bgcolor'} = $bgcolor;
+ $body_args{'no_title'} = 1;
+ $body_args{'force_register'} = 1;
+ $body_args{'add_entries'} = \%add_entries;
+ }
+
+ my $page_start = &Apache::loncommon::start_page($name,$extra_head,
+ \%body_args);
+
+ if (!defined($found{'body'})
+ && $env{'request.state'} ne 'construct'
+ && ($target eq 'web' || $target eq 'webgrade')) {
+
+ my ($symb,undef,undef,undef,$publicuser)= &Apache::lonxml::whichuser();
+ if ($symb eq '' && !$publicuser) {
+ my $help = &Apache::loncommon::help_open_topic("Ambiguous_Reference");
+ $help=&mt("Browsing resource, all submissions are temporary.")." ";
+ $page_start .= $help;
+ }
+ }
+
+ if (!defined($found{'body'})) {
+ $page_start .= &Apache::lonxml::message_location();
+ }
+
+ my $form_tag_start;
+ if (!defined($found{'form'})) {
+ $form_tag_start='
\n".&Apache::loncommon::end_page();
+}
+
+sub option {
+ my ($value,$name) = @_;
+ my $result ="
+ ".&option('CAN_ANSWER' ,'problemstate').&mt("Answerable")."
+ ".&option('CANNOT_ANSWER_tries' ,'problemstate').&mt("Open with full tries")."
+ ".&option('CANNOT_ANSWER_correct','problemstate').&mt("Open and correct")."
+ ".&option('SHOW_ANSWER' ,'problemstate').&mt("Show Answer")."
+
+
+
+Problem Type:
+
+
+
+Feedback Mode:
+
+
+
+";
+ my $numtoanalyze=$env{'form.numtoanalyze'};
+ if (!$numtoanalyze) { $numtoanalyze=20; }
+ $result.= ' for
+ '.&mt('versions of this problem').
+ '.'.&Apache::loncommon::help_open_topic("Analyze_Problem",
+ '',undef,undef,300).
+ '';
+ }
+ return $result;
+}
+
+sub initialize_storage {
+ %Apache::lonhomework::results=();
+ %Apache::lonhomework::history=();
+ my ($symb,$courseid,$domain,$name) = &Apache::lonxml::whichuser();
+ if ($env{'request.state'} eq 'construct'
+ || $symb eq ''
+ || $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') ||
+ $env{'form.newrandomization'} eq &mt('New Randomization')) {
+ &Apache::lonnet::tmpreset($namespace,'',$domain,$name);
+ &Apache::lonxml::debug("Attempt reset");
+ }
+ %Apache::lonhomework::history=
+ &Apache::lonnet::tmprestore($namespace,'',$domain,$name);
+ my ($temp)=keys %Apache::lonhomework::history ;
+ &Apache::lonxml::debug("Return message of $temp");
+ } else {
+ %Apache::lonhomework::history=
+ &Apache::lonnet::restore($symb,$courseid,$domain,$name);
+ }
+ #ignore error conditions
+ my ($temp)=keys %Apache::lonhomework::history ;
+ if ($temp =~ m/^error:.*/) { %Apache::lonhomework::history=(); }
+}
+
+# -------------------------------------------------------------finalize_storage
+# Stores away the result has to a student's environment
+# checks form.grade_ for specific values, other wises stores
+# to the running users environment
+# Will increment totals for attempts, students, and corrects
+# if running user has student role.
+sub finalize_storage {
+ my $result;
+ if (%Apache::lonhomework::results) {
+ my @remove = grep(/^INTERNAL_/,keys(%Apache::lonhomework::results));
+ delete(@Apache::lonhomework::results{@remove});
+ my ($symb,$courseid,$domain,$name) = &Apache::lonxml::whichuser();
+ if ($env{'request.state'} eq 'construct'
+ || $symb eq ''
+ || $Apache::lonhomework::type eq 'practice') {
+ my $namespace = $symb || $env{'request.uri'};
+ $Apache::lonhomework::results{'rndseed'}=$env{'form.rndseed'};
+ $result=&Apache::lonnet::tmpstore(\%Apache::lonhomework::results,
+ $namespace,'',$domain,$name);
+ &Apache::lonxml::debug('Construct Store return message:'.$result);
+ } else {
+ $result=&Apache::lonnet::cstore(\%Apache::lonhomework::results,
+ $symb,$courseid,$domain,$name);
+ &Apache::lonxml::debug('Store return message:'.$result);
+ if ($env{'request.role'} =~/^st/) {
+ &store_aggregates($symb,$courseid);
+ }
+ }
+ } else {
+ &Apache::lonxml::debug('Nothing to store');
+ }
+ return $result;
+}
+use Data::Dumper;
+
+# -------------------------------------------------------------store_aggregates
+# Sends hash of values to be incremented in nohist_resourcetracker.db
+# for the course. Increments total number of attempts, unique students
+# and corrects for each part for an instance of a problem, as appropriate.
+sub store_aggregates {
+ my ($symb,$courseid) = @_;
+ my %aggregate;
+ my @parts;
+ my $cdomain = $env{'course.'.$env{'request.course.id'}.'.domain'};
+ my $cname = $env{'course.'.$env{'request.course.id'}.'.num'};
+ foreach my $key (keys(%Apache::lonhomework::results)) {
+ if ($key =~ /resource\.([^\.]+)\.tries/) {
+ push(@parts, $1);
+ }
+ }
+ foreach my $part (@parts) {
+ if ($Apache::lonhomework::results{'resource.'.$part.'.award'}
+ eq 'APPROX_ANS' ||
+ $Apache::lonhomework::results{'resource.'.$part.'.award'}
+ eq 'EXACT_ANS') {
+ $aggregate{$symb."\0".$part."\0correct"} = 1;
+ }
+ if ($Apache::lonhomework::results{'resource.'.$part.'.tries'} == 1) {
+ $aggregate{$symb."\0".$part."\0users"} = 1;
+ } else {
+ my (undef,$last_reset) = &Apache::grades::get_last_resets($symb,$env{'request.course.id'},[$part]);
+ if ($last_reset) {
+ if (&Apache::grades::get_num_tries(\%Apache::lonhomework::history,$last_reset,$part) == 0) {
+ $aggregate{$symb."\0".$part."\0users"} = 1;
+ }
+ }
+ }
+ $aggregate{$symb."\0".$part."\0attempts"} = 1;
+ }
+ if (keys (%aggregate) > 0) {
+ &Apache::lonnet::cinc('nohist_resourcetracker',\%aggregate,
+ $cdomain,$cname);
+ }
+}
+
+sub checkout_msg {
+ my %lt=&Apache::lonlocal::texthash(
+ '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?');
+ return (<$lt{'resource'}
+
$lt{'id_expln'}
+
+
$lt{'warning'}
+
+
+ENDCHECKOUT
+}
+
+sub firstaccess_msg {
+ my ($time,$symb)=@_;
+ my ($map)=&Apache::lonnet::decode_symb($symb);
+ my $foldertitle=&Apache::lonnet::gettitle($map);
+ &Apache::lonxml::debug("map is $map title is $foldertitle");
+ return (<The resources in "$foldertitle" are open for a limited time. Once you click the 'Show Resource' button below you have $time to complete all resources "$foldertitle".
+
+ENDCHECKOUT
+}
+
+sub init_problem_globals {
+ my ($type)=@_;
+ #initialize globals
+ # For problems, we start out in part 0 (outside a tag).
+ # and part 0 is used to describe the main body of the
+ #
+ if ($type eq 'problem') {
+ $Apache::inputtags::part='0';
+ @Apache::inputtags::partlist=('0');
+ $Apache::lonhomework::problemstatus=&get_problem_status('0');
+ $Apache::lonhomework::ignore_response_errors=0;
+
+ } elsif ($type eq 'library') {
+ $Apache::inputtags::part='';
+ @Apache::inputtags::partlist=();
+ $Apache::lonhomework::problemstatus='';
+ $Apache::lonhomework::ignore_response_errors=1;
+
+ } elsif ($type eq 'Task') {
+ $Apache::inputtags::part='0';
+ @Apache::inputtags::partlist=('0');
+ $Apache::lonhomework::problemstatus='';
+ $Apache::lonhomework::ignore_response_errors=1;
+ }
+ @Apache::inputtags::responselist = ();
+ @Apache::inputtags::importlist = ();
+ @Apache::inputtags::previous=();
+ @Apache::inputtags::previous_version=();
+ $Apache::structuretags::printanswer='No';
+ @Apache::structuretags::whileconds=();
+ @Apache::structuretags::whilebody=();
+ @Apache::structuretags::whileline=();
+ $Apache::lonhomework::scantronmode=0;
+ undef($Apache::lonhomework::name);
+
+}
+
+sub reset_problem_globals {
+ my ($type)=@_;
+ undef(%Apache::lonhomework::history);
+ undef(%Apache::lonhomework::results);
+ undef($Apache::inputtags::part);
+#don't undef this, lonhomework.pm takes care of this, we use this to
+#detect if we try to do 2 problems in one file
+# undef($Apache::lonhomework::parsing_a_problem);
+ undef($Apache::lonhomework::name);
+}
+
+sub set_problem_state {
+ my ($part)=@_;
+ if ($env{'form.problemstate'} eq 'CANNOT_ANSWER_correct') {
+ $Apache::lonhomework::history{"resource.$part.solved"}=
+ 'correct_by_student';
+ }
+}
+
+sub get_problem_status {
+ my ($part)=@_;
+ my $problem_status;
+ if ($env{'request.state'} eq 'construct' &&
+ defined($env{'form.problemstatus'})) {
+ $problem_status=$env{'form.problemstatus'};
+ } else {
+ $problem_status=&Apache::lonnet::EXT("resource.$part.problemstatus");
+ &Apache::lonxml::debug("problem status for $part is $problem_status");
+ &Apache::lonxml::debug("env probstat is ".$env{'form.problemstatus'});
+ }
+ return $problem_status;
}
sub start_problem {
- my ($target,$token,$parstack,$parser,$safeeval)=@_;
- unless ($target eq 'meta') {
- my $args ='';
- if ( $#$parstack > -1 ) {
- $args=$$parstack[$#$parstack];
- }
- my $name = &Apache::run::run("{$args;".'return $name}',$safeeval);
- $Apache::inputtags::part='0';
- my $expression='$external::part='.$Apache::inputtags::part.';';
- $safeeval->share_from('Apache::inputtags',['@part']);
- &Apache::run::run($expression);
- return "$name\n\n\n";
- } else {
- if ($Apache::inputtags::part ne '0') {
- $result=&Apache::response::mandatory_part_meta;
+ my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
+ my $result;
+
+ if (!$Apache::lonxml::metamode) {
+ $result = &Apache::lonxml::endredirection(); #started in &start_problem
+ $Apache::lonxml::post_evaluate=0;
+ }
+
+ if ($target eq 'tex') {
+
+ # Figure out the front matter and replace the
+ # INSERTTEXFRONTMATTERHERE in result with it. note that we do
+ # this in end_problem because whether or not we display due
+ # dates depends on whether due dates have already been
+ # displayed in the problem parts.
+
+ my $frontmatter = '';
+ my $startminipage = '';
+ if (not $env{'form.problem_split'}=~/yes/) {
+ $startminipage = '\begin{minipage}{\textwidth}';
+ }
+ my $id = $Apache::inputtags::part;
+ my $weight = &Apache::lonnet::EXT("resource.$id.weight");
+ my $packages=&Apache::lonnet::metadata($env{'request.uri'},'packages');
+ my @packages = split /,/,$packages;
+ my $allow_print_points = 0;
+ foreach my $partial_key (@packages) {
+ if ($partial_key=~m/^part_0$/) {
+ $allow_print_points=1;
+ }
+ }
+ my $maxtries = &Apache::lonnet::EXT("resource.$id.maxtries");
+ if (defined($maxtries) && $maxtries < 0) { $allow_print_points=0; }
+ if (lc($env{'course.'.$env{'request.course.id'}.
+ '.disableexampointprint'}) eq 'yes') {
+ $allow_print_points=0;
+ }
+ my $name_of_resourse= &Apache::lonxml::latex_special_symbols(&get_resource_name($parstack,$safeeval),'header');
+ my $begin_doc='\begin{document} \typeout{STAMPOFPASSEDRESOURCESTART Resource
"'.$name_of_resourse.'"
located in '.$env{'request.uri'}.' STAMPOFPASSEDRESOURCEEND} \noindent ';
+ my $toc_line='\vskip 1 mm\noindent '.$startminipage.
+ '\addcontentsline{toc}{subsection}{'.$name_of_resourse.'}';
+
+ # Figure out what the due date is and if we need to print
+ # it in the problem header. We have been logging the
+ # last due date written to file.
+
+ my $duetime = &Apache::lonnet::EXT("resource.$id.duedate");
+ my $duedate = POSIX::strftime("%c",localtime($duetime));
+ my $temp_file;
+ my $filename = "/home/httpd/prtspool/$env{'user.name'}_$env{'user.domain'}_printout.due";
+
+ # Figure out what the last printed due date is or set it
+ # to the epoch if no duedates have been printed.
+
+ my $due_file_content = 0; # If the file does not yet exist, time is the epoch.
+ if (-e $filename) {
+ $temp_file = Apache::File->new($filename);
+ my @due_file = <$temp_file>;
+ $due_file_content = $due_file[$#due_file];
+ chomp $due_file_content;
+ }
+
+ # We display the due date iff it is not the same as the last
+ # duedate in problem header ($due_file_content), and
+ # none of our parts displayed a duedate.
+ #
+ my $parts_with_displayduedate;
+ if (defined $Apache::outputtags::showonce{'displayduedate'}) {
+ $parts_with_displayduedate =
+ scalar(@{$Apache::outputtags::showonce{'displayduedate'}});
+ } else {
+ $parts_with_displayduedate = 0;
+ }
+ if (($due_file_content != $duetime) && ($parts_with_displayduedate == 0) ) {
+ $temp_file = Apache::File->new('>'.$filename);
+ print $temp_file "$duetime\n";
+ if (not $env{'request.symb'} =~ m/\.page_/) {
+ if(not $duedate=~m/1969/ and $Apache::lonhomework::type ne 'exam') {
+ $frontmatter .= $begin_doc.
+ '\textit{Due date: '.$duedate.'} '.$toc_line;
+ } else {
+ $frontmatter.= $begin_doc.$toc_line;
+ if ($Apache::lonhomework::type eq 'exam' and $allow_print_points==1) { $frontmatter .= '\fbox{\textit{'.$weight.' pt}}';}
+ }
+ } else {
+ $frontmatter .= '\vskip 1mm\textit{Due date: '.$duedate.'} \\\\\\\\';
+ }
+ } else {
+ if (not $env{'request.symb'} =~ m/\.page_/) {
+ $frontmatter .= $begin_doc.$toc_line;
+ if (($Apache::lonhomework::type eq 'exam') and ($allow_print_points==1)) { $frontmatter .= '\fbox{\textit{'.$weight.' pt}}';}
+ } else {
+ $frontmatter .= '\vskip 1mm \\\\\\\\';
+ }
+ }
+ $result =~ s/INSERTTEXFRONTMATTERHERE/$frontmatter/;
}
- }
- return $result;
+
+ my $status=$Apache::inputtags::status['-1'];
+ if ($target eq 'grade' || $target eq 'web' || $target eq 'answer' ||
+ $target eq 'tex') {
+ if ( $target eq 'grade' && $Apache::inputtags::part eq '0') {
+ # if part is zero, no s existed, so we need to the grading
+ if ($status eq 'CAN_ANSWER' ||$Apache::lonhomework::scantronmode) {
+ &Apache::inputtags::grade;
+ } elsif ($status eq 'NEEDS_CHECKIN') {
+ # no need to grade, and don't want to hide data
+ } else {
+ # move any submission data to .hidden
+ &Apache::inputtags::hidealldata($Apache::inputtags::part);
+ }
+ } elsif ( ($target eq 'web' || $target eq 'tex') &&
+ $Apache::inputtags::part eq '0' &&
+ $status ne 'UNCHECKEDOUT' && $status ne 'NOT_YET_VIEWED') {
+ # if part is zero, no s existed, so we need show the current
+ # grading status
+ my $gradestatus = &Apache::inputtags::gradestatus($Apache::inputtags::part,$target);
+ $result.= $gradestatus;
+ }
+ if (
+ (($target eq 'web') && ($env{'request.state'} ne 'construct')) ||
+ ($target eq 'answer') || ($target eq 'tex')
+ ) {
+ if ($target ne 'tex' &&
+ $env{'form.answer_output_mode'} ne 'tex') {
+ $result.="";
+ $result.=&Apache::lonhtmlcommon::htmlareaselectactive(@Apache::lonxml::htmlareafields);
+ }
+ if ($target eq 'web') {
+ $result.=&Apache::lonxml::xmlend().'';
+ } elsif ($target eq 'tex') {
+ my $endminipage = '';
+ if (not $env{'form.problem_split'}=~/yes/) {
+ $endminipage = '\end{minipage}';
+ }
+ if ($env{'form.print_discussions'} eq 'yes') {
+ $result.=&Apache::lonxml::xmlend($target,$parser);
+ $result=~s/<\/html>//;
+ } else {
+ $result .= '\keephidden{ENDOFPROBLEM}\vskip 0.5mm\noindent\makebox[\textwidth/$number_of_columns][b]{\hrulefill}';
+ if (not $env{'request.symb'} =~ m/\.page_/) {
+ $result .= $endminipage.'\end{document} ';
+ } else {
+ $result .= '';
+ }
+ }
+ }
+ }
+ if ($target eq 'grade') {
+ &Apache::lonhomework::showhash(%Apache::lonhomework::results);
+ &finalize_storage();
+ }
+ if ($target eq 'answer' && ($env{'request.state'} eq 'construct')
+ && $env{'form.answer_output_mode'} ne 'tex') {
+ $result.=&Apache::lonxml::xmlend().'