--- loncom/homework/radiobuttonresponse.pm 2012/01/20 13:26:34 1.154 +++ loncom/homework/radiobuttonresponse.pm 2012/02/10 00:26:42 1.155 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # mutliple choice style responses # -# $Id: radiobuttonresponse.pm,v 1.154 2012/01/20 13:26:34 raeburn Exp $ +# $Id: radiobuttonresponse.pm,v 1.155 2012/02/10 00:26:42 foxr Exp $ # # Copyright Michigan State University Board of Trustees # @@ -33,14 +33,22 @@ use HTML::Entities(); use Apache::lonlocal; use Apache::lonnet; use Apache::response; +use Apache::caparesponse; my $default_bubbles_per_line = 10; +my @alphabet = ( 'A' .. 'Z' ); # Foil labels. + + BEGIN { &Apache::lonxml::register('Apache::radiobuttonresponse',('radiobuttonresponse')); } +#--------------------------------------------------------------------------- +# +# Generic utility subs. + sub bubble_line_count { my ($numfoils, $bubbles_per_line) = @_; my $bubble_lines; @@ -53,6 +61,10 @@ sub bubble_line_count { } + +#------------------------------------------------------------------------------ +# +# XML handlers. sub start_radiobuttonresponse { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result; @@ -90,27 +102,30 @@ sub start_radiobuttonresponse { $safeeval,'max', 'randomize','direction'); if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); } - } elsif ($target eq 'tex') { - my $type=&Apache::lonxml::get_param('TeXtype',$parstack,$safeeval, - undef,0); - if ($type eq '1') { - $result .= ' \renewcommand{\labelenumi}{\arabic{enumi}.}'; - } elsif ($type eq 'A') { - $result .= ' \renewcommand{\labelenumi}{\Alph{enumi}.}'; - } elsif ($type eq 'a') { - $result .= ' \renewcommand{\labelenumi}{\alph{enumi}.}'; - } elsif ($type eq 'i') { - $result .= ' \renewcommand{\labelenumi}{\roman{enumi}.}'; - } else { - $result .= ' \renewcommand{\labelenumi}{\Alph{enumi}.}'; - } - if($env{'form.pdfFormFields'} eq 'yes' && $Apache::inputtags::status[-1] eq 'CAN_ANSWER') { - $result .= '\begin{itemize}'; - } else { - $result .= '\begin{enumerate}'; + + } elsif ( $target eq 'tex' ) { + my $type = + &Apache::lonxml::get_param( 'TeXtype', $parstack, $safeeval, undef, + 0 ); + if ( $type eq '1' ) { + $result .= ' \renewcommand{\labelenumi}{\arabic{enumi}.}'; + } + elsif ( $type eq 'A' ) { + $result .= ' \renewcommand{\labelenumi}{\Alph{enumi}.}'; + } + elsif ( $type eq 'a' ) { + $result .= ' \renewcommand{\labelenumi}{\alph{enumi}.}'; + } + elsif ( $type eq 'i' ) { + $result .= ' \renewcommand{\labelenumi}{\roman{enumi}.}'; } - } elsif ($target eq 'analyze') { - my $part_id="$Apache::inputtags::part.$id"; + else { + $result .= ' \renewcommand{\labelenumi}{\Alph{enumi}.}'; + } + + } + elsif ( $target eq 'analyze' ) { + my $part_id = "$Apache::inputtags::part.$id"; $Apache::lonhomework::analyze{"$part_id.type"} = 'radiobuttonresponse'; push (@{ $Apache::lonhomework::analyze{"parts"} },$part_id); } @@ -120,13 +135,8 @@ sub start_radiobuttonresponse { sub end_radiobuttonresponse { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result; - if ($target eq 'edit') { $result=&Apache::edit::end_table(); } - if ($target eq 'tex' ) { - if($env{'form.pdfFormFields'} eq 'yes' and $Apache::inputtags::status[-1] eq 'CAN_ANSWER') { - $result .= '\end{itemize}'; - } else { - $result .= '\end{enumerate}'; - } + if ( $target eq 'edit' ) { + $result = &Apache::edit::end_table(); } &Apache::response::end_response; pop @Apache::lonxml::namespace; @@ -223,6 +233,7 @@ sub end_foilgroup { my $part = $Apache::inputtags::part; my $bubbles_per_line = &getbubblesnum($part,$id); + if ($target eq 'grade' || $target eq 'web' || $target eq 'answer' || $target eq 'tex' || $target eq 'analyze') { my $style = $Apache::lonhomework::type; @@ -285,7 +296,6 @@ sub end_foilgroup { } return $result; } - sub getbubblesnum { my ($part,$id) = @_; my $bubbles_per_line; @@ -328,112 +338,313 @@ sub format_prior_answer { } -sub displayallfoils { - my ($direction, $target)=@_; - my $result; - &Apache::lonxml::debug("survey style display"); - my @names; - if ( $Apache::response::foilgroup{'names'} ) { - @names= @{ $Apache::response::foilgroup{'names'} }; - } - my $temp=0; - my $i =0; - my $id=$Apache::inputtags::response['-1']; - my $part=$Apache::inputtags::part; - my ($lastresponse,$newvariation,$showanswer); - if ((($Apache::lonhomework::history{"resource.$part.type"} eq 'randomizetry') || - ($Apache::lonhomework::type eq 'randomizetry')) && - ($Apache::inputtags::status[-1] eq 'CAN_ANSWER')) { - if ($env{'form.'.$part.'.rndseed'} ne - $Apache::lonhomework::history{"resource.$part.rndseed"}) { +## +# Return the last survey response. The logic is slightly different than that of +# get_last_responses. TODO: See if there are chunks of code betweenthis and +# get_last_reponses that are common and can be factored. +# +# @param $part - Problem part under consideration. +# @param $showanswer - True if answers should be shown. +# @param $id - Problem id. +# +# @return hash reference. +# @retval reference to the has indexed by answer selection that +# indicates the most recent answer. +# +sub get_last_survey_response { + my ($part, $showanswer, $id) = @_; + + my $newvariation; + my $lastresponse; # stringified last response. + + if ( + ( + ( + $Apache::lonhomework::history{"resource.$part.type"} eq + 'randomizetry' + ) + || ( $Apache::lonhomework::type eq 'randomizetry' ) + ) + && ( $Apache::inputtags::status[-1] eq 'CAN_ANSWER' ) + ) + { + if ( $env{ 'form.' . $part . '.rndseed' } ne + $Apache::lonhomework::history{"resource.$part.rndseed"} ) + { $newvariation = 1; } } $showanswer = &Apache::response::show_answer(); - unless ((($Apache::lonhomework::history{"resource.$part.type"} eq 'anonsurvey') || ($Apache::lonhomework::history{"resource.$part.type"} eq 'anonsurveycred')) && (defined($env{'form.grade_symb'})) || - ($newvariation && !$showanswer)) { - $lastresponse = - $Apache::lonhomework::history{"resource.$part.$id.submission"}; + unless ( + ( + ( + $Apache::lonhomework::history{"resource.$part.type"} eq + 'anonsurvey' + ) + || ( $Apache::lonhomework::history{"resource.$part.type"} eq + 'anonsurveycred' ) + ) + && ( defined( $env{'form.grade_symb'} ) ) + || ( $newvariation && !$showanswer ) + ) + { + $lastresponse = + $Apache::lonhomework::history{"resource.$part.$id.submission"}; + } + my %lastresponse = &Apache::lonnet::str2hash($lastresponse); + + + return \%lastresponse; + +} +## +# Removes the names from a foil group that are marked as unused. +# +# @param $names - reference to the array of names to filter. +# +# @return arrayref +# @retval reference to the filtered array. +# +sub remove_unused { + my ($names) = @_; + my @result; + + foreach my $name (@{$names}) { + if ($Apache::response::foilgroup{$name . '.value'} ne 'unused') { + push(@result, $name); + } + } + return \@result; +} +## +# Displays all foils in a survey type problem for HTML rendition. +# TODO: See if there is any logic in this sub that can be shared +# with display_foils_html +# +# @param $names - ref to array of names of the foils to display. +# @param $part - Problem part number. +# @param $showanswer - If true, show the answers. +# @param $lastresponse - Ref to the last response hash. +# @param $direction - Display direction of the radiobuttons. +# +# @return string +# @retval HTML required to display the resource in a browser. +# +sub display_survey_html { + my ($names, $part, $showanswer, $lastresponse, $direction) = @_; + my $result; + + # Figure out a few fragments of html that depend onthe + # orientation of the radiobuttons: + # closing_html - HTML to emit at the end of the resource. + # pre_foil - HTML to emit prior to each foil. + # post_foil - HTML to emit following each foil. + # + # The opening HTML is just added to the $result now + # + # Figuring these outin advance compresses the loop over foils into something + # pretty simple: + # + # NOTE: There's probably a really cool way to do this with style sheets + # and picking the selector based on the orientation, if someone wants to puzzle + # that out. In that case, probably the whole thing lives in a
+ # + + + my ($opening_html, $closing_html, $pre_foil, $post_foil) = + &html_direction_fragments($direction); + + $result = $opening_html; + + # Different rendering depending on whether answers are shown: + # I played with different factorings but this seems the most concise/clear... + # although I don't like the $showanswer conditino inside the loop. Other things I tried + # - two loops..much longer code..no gain in clarity. + # - Using a visitor patttern passing it the rendering code chunklets and + # an anonymous hash reference for state data etc. Very cool but + # quite a bit more code and quite a bit less clear. + + my $temp = 0; + foreach my $name (@{$names}) { + $result .= $pre_foil; + + if ($showanswer) { + my $foiltext = $Apache::response::foilgroup{$name . '.text'}; + + # Bold the prior response: + + if (defined($lastresponse->{$name})) { + $result .= '' . $foiltext . ''; + } else { + $result .= $foiltext; + } + } else { + $result .= &html_radiobutton( + $part, $Apache::inputtags::response['-1'], $name, $lastresponse, $temp + ); + } + + $result .= $post_foil; + $temp++; } - if ($direction eq 'horizontal') { $result.='
";
- } else {
- if ($target eq 'tex') {
- $result .= '\item \vskip -2mm ';
- } else {
- $result.=" "; - } - } - if (defined($lastresponse{$name})) { - if ($target eq 'tex') { - $result .= '}'; - } else { - $result.=''; - } - } - $result .= $Apache::response::foilgroup{$name.'.text'}; - if (defined($lastresponse{$name}) && ($target ne 'tex')) { - $result.=''; - } - if (($direction eq 'horizontal') && ($target ne 'tex')) { $result.=" | "; }
+ $result .= "\\begin{$venv}";
+ foreach my $name (@{$names}) {
+
+
+ $result .= '\item \vskip -2mm ';
+
+ if ( defined( $lastresponse->{$name} ) ) {
+ $result .= '}';
}
+ $result .= $Apache::response::foilgroup{ $name . '.text' } . ' ';
}
+ $result .= "\\end{$venv}";
+
+ } elsif ( $env{'form.pdfFormFields'} eq 'yes'
+ && $Apache::inputtags::status[-1] eq 'CAN_ANSWER') {
+ $result .= &display_pdf_form($names, $direction, $venv);
} else {
- foreach my $name (@names) {
- if ($Apache::response::foilgroup{$name.'.value'} ne 'unused') {
- if ($direction eq 'horizontal') {
- $result.="";
- } else {
- if ($target eq 'tex') {
- if($env{'form.pdfFormFields'} eq 'yes' && $Apache::inputtags::status[-1] eq 'CAN_ANSWER') {
- my $fieldname = $env{'request.symb'}.'&part_'. $Apache::inputtags::part
- .'&radiobuttonresponse'.'&HWVAL_'.$Apache::inputtags::response['-1'];
- $result .= '\item[{'.&Apache::lonxml::print_pdf_radiobutton($fieldname,$temp).'}]'
- .$Apache::response::foilgroup{$name.'.text'}."\n";
- } else {
- $result .= '\item \vskip -2mm ';
- }
- } else {
- $result.=" "; - } - } - if ($target eq 'tex') { - if($env{'form.pdfFormFields'} ne 'yes' or $Apache::inputtags::status[-1] ne 'CAN_ANSWER') { - $result .= '$\bigcirc$'.$Apache::response::foilgroup{$name.'.text'}.'\\\\'; #' stupid emacs - } - $i++; - } else { - $result .= ' | "; }
- } else {
- $result.='\vskip 0 mm ';
- }
+
+ $result .= '\vskip 0 mm ';
}
- }
+ $result .= "\\end{$venv}";
+ }
}
-
- if (($direction eq 'horizontal') && ($target ne 'tex')) { $result.='
'; }
+
+ # Web rendition encloses the
+ # item text in a label tag as well:
+
+ if ($target eq 'web') {
+ $result .= '' . $item_closetag;
}
- if ($target ne 'tex') {
- $result.=" "; - } else { - $result.='\item \vskip -2 mm '; + $result .= $Apache::response::foilgroup{$name . '.text'}; + $result .= $item_closetag; + $result .= $item_posttext; + $result .= "\n"; # make the html a bit more readable. + } + + + } else { + my $lastresponse = &get_last_response($part); + + my $item_no = 0; + foreach my $name (@{$whichfoils}) { + $result .= $item_pretext; + $result .= &html_radiobutton( + $part, $Apache::inputtags::response[-1], + $name, $lastresponse, $item_no + ); + $result .= $item_posttext; + $item_no++; + } + + } + $result .= $finalclose; + + return $result; +} +## +# Display foils in exam mode for latex +# +# @param $whichfoils - Reference to an array that contains the foil names to display +# @param $bubbles_per_line - Number of bubbles on a line. +# @param $direction - Rendering direction 'horizontal' is what we're looking for. +# @param $venv - Name of LaTeX environment to use for vertical rendering. +# +# @return string +# @return the latex rendering of the exam problem. +# +# +sub display_latex_exam { + my ($whichfoils, $bubbles_per_line, $direction, $venv) = @_; + my $result; + my $numlines; + my $bubble_number = 0; + my $line = 0; + my $i = 0; + + + if ($direction eq 'horizontal') { + + # Marshall the display text for each foil and turn things over to + # Apache::response::make_horizontal_bubbles: + + my @foil_texts = &get_foil_texts($whichfoils); + $result .= &Apache::caparesponse::make_horizontal_latex_bubbles( + $whichfoils, \@foil_texts, '$\bigcirc$'); + + } else { + + $result .= '\vskip 2mm \noindent'; + + # This section puts out the prefix that tells the user + # (if necessary) to only choose one bubble in the next n lines + # for problems with more than one line worth of bubbles in the grid sheet: + + my $numitems = scalar( @{$whichfoils} ); + $numlines = int( $numitems / $bubbles_per_line ); + if ( ( $numitems % $bubbles_per_line ) != 0 ) { + $numlines++; + } + if ( $numlines < 1 ) { + $numlines = 1; + } + if ( $numlines > 1 ) { + my $linetext; + for ( my $i = 0 ; $i < $numlines ; $i++ ) { + $linetext .= $Apache::lonxml::counter + $i . ', '; } - if ($Apache::response::foilgroup{$name.'.value'} eq 'true') { - if ($target ne 'tex') { - $result.=&mt('Correct:').''; - } else { - $result.=&mt('Correct:').' \textbf{'; - } - } else { - $result.=&mt('Incorrect:'); + $linetext =~ s/,\s$//; + $result .= + '\small {\textbf{' + . $linetext . '}} ' + . ' {\footnotesize ' + . &mt( '(Bubble once in [_1] lines)', $numlines ) + . '} \hspace*{\fill} \\\\'; + } + else { + $result .= '\textbf{' . $Apache::lonxml::counter . '}.'; + } + + # Now output the bubbles themselves: + + foreach my $name (@{$whichfoils}) { + if ( $bubble_number >= $bubbles_per_line ) { + $line++; + $i = 0; + $bubble_number = 0; } - if ($target eq 'web') { $result.=""; } - if ($Apache::response::foilgroup{$name.'.value'} eq 'true') { - if ($target ne 'tex') { $result.='';} else {$result.='}';} + my $identifier; + if ( $numlines > 1 ) { + $identifier = $Apache::lonxml::counter + $line; } - if ($direction eq 'horizontal') { - if ($target ne 'tex') { $result.=' | '; }
+ my $preindent;
+ if ($bubble_number > 0) {
+ $preindent = '\hspace*{3 mm}';
}
+ my $foiltext = $Apache::response::foilgroup{$name . '.text'};
+ $foiltext =~ s/\\noindent//; # forgive me for I have sinned..
+ $result .= '{\small \textbf{'
+ . $identifier .$preindent
+ . $alphabet[$i]
+ . '}}$\bigcirc$'
+ . $foiltext
+ . '\\\\'; #' stupid emacs -- it thinks it needs that apostrophe to close the quote
+
+ $i++;
+ $bubble_number++;
}
- if ($direction eq 'horizontal') {
- if ($target ne 'tex') {
- $result.='
";
- } else {
- $result.=" "; - } - } - if ($target ne 'tex') { - $result.= ' | ";
+ $result .= &display_latex($whichfoils, $direction, $vertical_env );
}
- $temp++;
- }
- if ($target ne 'tex' && $direction eq 'horizontal') {
- $result.="
The server encountered an internal error or misconfiguration and was unable to complete your request.
Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.
More information about this error may be available in the server error log.