Annotation of loncom/homework/radiobuttonresponse.pm, revision 1.155

1.22      albertel    1: # The LearningOnline Network with CAPA
                      2: # mutliple choice style responses
1.31      albertel    3: #
1.155   ! foxr        4: # $Id: radiobuttonresponse.pm,v 1.153.6.10 2012/02/05 16:11:57 foxr Exp $
1.31      albertel    5: #
                      6: # Copyright Michigan State University Board of Trustees
                      7: #
                      8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
                      9: #
                     10: # LON-CAPA is free software; you can redistribute it and/or modify
                     11: # it under the terms of the GNU General Public License as published by
                     12: # the Free Software Foundation; either version 2 of the License, or
                     13: # (at your option) any later version.
                     14: #
                     15: # LON-CAPA is distributed in the hope that it will be useful,
                     16: # but WITHOUT ANY WARRANTY; without even the implied warranty of
                     17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     18: # GNU General Public License for more details.
                     19: #
                     20: # You should have received a copy of the GNU General Public License
1.130     foxr       21: # along with LON-CAPA; if not, write to the Free Software# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
1.31      albertel   22: #
                     23: # /home/httpd/html/adm/gpl.txt
                     24: #
                     25: # http://www.lon-capa.org/
                     26: #
1.1       albertel   27: 
1.154     raeburn    28: 
                     29: 
1.1       albertel   30: package Apache::radiobuttonresponse;
                     31: use strict;
1.42      albertel   32: use HTML::Entities();
1.85      albertel   33: use Apache::lonlocal;
1.100     albertel   34: use Apache::lonnet;
1.115     foxr       35: use Apache::response;
1.155   ! foxr       36: use Apache::caparesponse;
1.1       albertel   37: 
1.120     foxr       38: my $default_bubbles_per_line = 10;
1.155   ! foxr       39: my @alphabet      = ( 'A' .. 'Z' ); # Foil labels.
        !            40: 
        !            41: 
1.121     foxr       42: 
1.154     raeburn    43: 
1.36      harris41   44: BEGIN {
1.154     raeburn    45:     &Apache::lonxml::register('Apache::radiobuttonresponse',('radiobuttonresponse'));
1.1       albertel   46: }
                     47: 
1.155   ! foxr       48: #---------------------------------------------------------------------------
        !            49: #
        !            50: #  Generic utility subs.
        !            51: 
1.121     foxr       52: sub bubble_line_count {
1.154     raeburn    53:     my ($numfoils, $bubbles_per_line) = @_;
1.121     foxr       54:     my $bubble_lines;
1.154     raeburn    55:     $bubble_lines = int($numfoils / $bubbles_per_line);
                     56:     if (($numfoils % $bubbles_per_line) != 0) {
                     57: 	$bubble_lines++;
1.121     foxr       58:     }
                     59:     return $bubble_lines;
1.154     raeburn    60:     
                     61: }
1.153     foxr       62: 
1.121     foxr       63: 
1.155   ! foxr       64: 
        !            65: #------------------------------------------------------------------------------
        !            66: #
        !            67: #  XML handlers.
1.1       albertel   68: sub start_radiobuttonresponse {
1.154     raeburn    69:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
1.83      albertel   70:     my $result;
1.115     foxr       71: 
1.83      albertel   72:     #when in a radiobutton response use these
1.154     raeburn    73:     &Apache::lonxml::register('Apache::radiobuttonresponse',('foilgroup','foil','conceptgroup'));
                     74:     push (@Apache::lonxml::namespace,'radiobuttonresponse');
                     75:     my $id = &Apache::response::start_response($parstack,$safeeval);
1.120     foxr       76: 
1.154     raeburn    77:     %Apache::hint::radiobutton=();
1.85      albertel   78:     undef(%Apache::response::foilnames);
1.154     raeburn    79:     if ($target eq 'meta') {
                     80: 	$result=&Apache::response::meta_package_write('radiobuttonresponse');
                     81:     } elsif ($target eq 'edit' ) {
                     82: 	$result.=&Apache::edit::start_table($token)
                     83:            .'<tr><td>'.&Apache::lonxml::description($token)
                     84:            .&Apache::loncommon::help_open_topic('Radio_Response_Problems')
                     85:            .'</td>'
                     86:            .'<td><span class="LC_nobreak">'.&mt('Delete?').' '
                     87:            .&Apache::edit::deletelist($target,$token)
                     88:            .'</span></td>'
                     89:            .'<td>&nbsp;'.&Apache::edit::end_row()
                     90:            .&Apache::edit::start_spanning_row();
                     91: 	$result.=
                     92: 	    &Apache::edit::text_arg('Max Number Of Shown Foils:','max',
                     93: 				    $token,'4').'&nbsp;'x 3 .
                     94: 	    &Apache::edit::select_arg('Randomize Foil Order:','randomize',
                     95: 				      ['yes','no'],$token).'&nbsp;'x 3 .
                     96: 	    &Apache::edit::select_arg('Display Direction:','direction',
                     97: 				      ['vertical','horizontal'],$token).
                     98: 				      &Apache::edit::end_row().
                     99: 				      &Apache::edit::start_spanning_row()."\n";
                    100:     } elsif ($target eq 'modified') {
                    101: 	my $constructtag=&Apache::edit::get_new_args($token,$parstack,
                    102: 						     $safeeval,'max',
                    103: 						     'randomize','direction');
                    104: 	if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); }
1.155   ! foxr      105: 
        !           106:    } elsif ( $target eq 'tex' ) {
        !           107:         my $type =
        !           108:           &Apache::lonxml::get_param( 'TeXtype', $parstack, $safeeval, undef,
        !           109:             0 );
        !           110:         if ( $type eq '1' ) {
        !           111:             $result .= ' \renewcommand{\labelenumi}{\arabic{enumi}.}';
        !           112:         }
        !           113:         elsif ( $type eq 'A' ) {
        !           114:             $result .= ' \renewcommand{\labelenumi}{\Alph{enumi}.}';
        !           115:         }
        !           116:         elsif ( $type eq 'a' ) {
        !           117:             $result .= ' \renewcommand{\labelenumi}{\alph{enumi}.}';
        !           118:         }
        !           119:         elsif ( $type eq 'i' ) {
        !           120:             $result .= ' \renewcommand{\labelenumi}{\roman{enumi}.}';
        !           121:         }
        !           122:         else {
        !           123:             $result .= ' \renewcommand{\labelenumi}{\Alph{enumi}.}';
1.135     onken     124:         }
1.155   ! foxr      125: 
        !           126:     }
        !           127:     elsif ( $target eq 'analyze' ) {
        !           128:         my $part_id = "$Apache::inputtags::part.$id";
1.131     raeburn   129:         $Apache::lonhomework::analyze{"$part_id.type"} = 'radiobuttonresponse';
1.154     raeburn   130: 	push (@{ $Apache::lonhomework::analyze{"parts"} },$part_id);
1.83      albertel  131:     }
                    132:     return $result;
1.1       albertel  133: }
                    134: 
                    135: sub end_radiobuttonresponse {
1.154     raeburn   136:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
1.83      albertel  137:     my $result;
1.155   ! foxr      138:     if ( $target eq 'edit' ) { 
        !           139: 	$result = &Apache::edit::end_table(); 
1.135     onken     140:     }
1.83      albertel  141:     &Apache::response::end_response;
                    142:     pop @Apache::lonxml::namespace;
1.154     raeburn   143:     &Apache::lonxml::deregister('Apache::radiobuttonresponse',('foilgroup','foil','conceptgroup'));
1.85      albertel  144:     undef(%Apache::response::foilnames);
1.83      albertel  145:     return $result;
1.1       albertel  146: }
                    147: 
1.154     raeburn   148: %Apache::response::foilgroup=();
1.1       albertel  149: sub start_foilgroup {
1.154     raeburn   150:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                    151:     %Apache::response::foilgroup=();
                    152:     $Apache::radiobuttonresponse::conceptgroup=0;
                    153:     &Apache::response::pushrandomnumber(undef,$target);
1.151     raeburn   154:     return;
1.5       albertel  155: }
                    156: 
1.15      albertel  157: sub storesurvey {
1.144     raeburn   158:     my ($style) = @_;
1.99      albertel  159:     if ( !&Apache::response::submitted() ) { return ''; }
1.154     raeburn   160:     my $response = $env{'form.HWVAL_'.$Apache::inputtags::response['-1']};
1.83      albertel  161:     &Apache::lonxml::debug("Here I am!:$response:");
1.154     raeburn   162:     if ( $response !~ /[0-9]+/) { return ''; }
                    163:     my $part = $Apache::inputtags::part;
                    164:     my $id = $Apache::inputtags::response['-1'];
                    165:     my @whichfoils=@{ $Apache::response::foilgroup{'names'} };
1.83      albertel  166:     my %responsehash;
1.154     raeburn   167:     $responsehash{$whichfoils[$response]}=$response;
                    168:     my $responsestr=&Apache::lonnet::hash2str(%responsehash);
                    169:     $Apache::lonhomework::results{"resource.$part.$id.submission"}=
                    170: 	$responsestr;
                    171:     my %previous=&Apache::response::check_for_previous($responsestr,$part,$id);
1.144     raeburn   172:     my $ad;
1.154     raeburn   173:     if ($style eq 'anonsurvey') {
                    174:         $ad=$Apache::lonhomework::results{"resource.$part.$id.awarddetail"}='ANONYMOUS';
                    175:     } elsif ($style eq 'anonsurveycred') {
                    176:         $ad=$Apache::lonhomework::results{"resource.$part.$id.awarddetail"}='ANONYMOUS_CREDIT';
                    177:     } elsif ($style eq 'surveycred') {
                    178:         $ad=$Apache::lonhomework::results{"resource.$part.$id.awarddetail"}='SUBMITTED_CREDIT';
                    179:     } else {
                    180:         $ad=$Apache::lonhomework::results{"resource.$part.$id.awarddetail"}='SUBMITTED';
1.144     raeburn   181:     }
1.154     raeburn   182:     &Apache::response::handle_previous(\%previous,$ad);
1.83      albertel  183:     &Apache::lonxml::debug("submitted a $response<br />\n");
                    184:     return '';
1.15      albertel  185: }
                    186: 
1.154     raeburn   187: 
1.32      albertel  188: sub grade_response {
1.154     raeburn   189:     my ($answer, $whichfoils, $bubbles_per_line)=@_;
1.123     albertel  190: 
1.99      albertel  191:     if ( !&Apache::response::submitted() ) { return; }
1.83      albertel  192:     my $response;
1.154     raeburn   193:     
                    194:     if ($env{'form.submitted'} eq 'scantron') {
                    195: 	$response = &Apache::response::getresponse(1,undef,
                    196: 						   &bubble_line_count(scalar(@{ $whichfoils}),
                    197: 								      $bubbles_per_line),
                    198: 						   $bubbles_per_line);
1.116     foxr      199: 
1.154     raeburn   200:     } else {
                    201: 	$response = $env{'form.HWVAL_'.$Apache::inputtags::response['-1']};
                    202:     }
1.153     foxr      203: 
1.120     foxr      204: 
1.154     raeburn   205:     if ( $response !~ /[0-9]+/) { return; }
                    206:     my $part=$Apache::inputtags::part;
                    207:     my $id = $Apache::inputtags::response['-1'];
1.83      albertel  208:     my %responsehash;
1.154     raeburn   209:     $responsehash{$whichfoils->[$response]}=$response;
                    210:     my $responsestr=&Apache::lonnet::hash2str(%responsehash);
                    211:     my %previous=&Apache::response::check_for_previous($responsestr,
                    212: 						       $part,$id);
                    213:     $Apache::lonhomework::results{"resource.$part.$id.submission"}=
                    214: 	$responsestr;
1.83      albertel  215:     &Apache::lonxml::debug("submitted a $response<br />\n");
                    216:     my $ad;
1.154     raeburn   217:     if ($response == $answer) {
                    218: 	$ad='EXACT_ANS';
                    219:     } else {
                    220: 	$ad='INCORRECT';
1.83      albertel  221:     }
1.154     raeburn   222:     $Apache::lonhomework::results{"resource.$part.$id.awarddetail"}=$ad;
                    223:     &Apache::response::handle_previous(\%previous,$ad);
1.32      albertel  224: }
                    225: 
1.1       albertel  226: sub end_foilgroup {
1.154     raeburn   227:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
1.29      albertel  228: 
1.83      albertel  229:     my $result;
1.121     foxr      230:     my $bubble_lines;
                    231:     my $answer_count;
1.154     raeburn   232:     my $id   = $Apache::inputtags::response['-1'];
                    233:     my $part = $Apache::inputtags::part;
                    234:     my $bubbles_per_line = &getbubblesnum($part,$id);
1.153     foxr      235: 
1.155   ! foxr      236: 
1.154     raeburn   237:     if ($target eq 'grade' || $target eq 'web' || $target eq 'answer' ||
                    238: 	$target eq 'tex' || $target eq 'analyze') {
                    239: 	my $style = $Apache::lonhomework::type;
                    240: 	my $direction = &Apache::lonxml::get_param('direction',$parstack,
                    241: 						   $safeeval,'-2');
                    242: 	if ( (($style eq 'survey') || ($style eq 'surveycred') || 
                    243:               ($style eq 'anonsurvey') || ($style eq 'anonsurveycred')) 
                    244:              && ($target ne 'analyze')) {
                    245: 	    if ($target eq 'web' || $target eq 'tex') {
                    246: 		$result=&displayallfoils($direction, $target);
                    247: 	    } elsif ( $target eq 'answer' ) {
                    248: 		$result=&displayallanswers();
                    249: 	    } elsif ( $target eq 'grade' ) {
                    250: 		$result=&storesurvey($style);
                    251: 	    }
                    252: 	    $answer_count = scalar(@{$Apache::response::foilgroup{'names'}});
                    253: 
                    254: 	} else {
                    255: 
                    256: 	    my $name;
                    257: 	    my $max = &Apache::lonxml::get_param('max',$parstack,$safeeval,
                    258: 						 '-2');
                    259: 	    my $randomize = &Apache::lonxml::get_param('randomize',$parstack,
                    260: 						       $safeeval,'-2');
                    261: 	    my ($answer, @shown) = &whichfoils($max, $randomize);
                    262: 	    $answer_count = scalar(@shown);
                    263: 
                    264: 	    if ($target eq 'web' || $target eq 'tex') {
                    265:                 $result=&displayfoils($target,
                    266: 				      $answer, \@shown,
                    267: 				      $direction,
                    268: 				      $bubbles_per_line);
                    269: 	    } elsif ($target eq 'answer' ) {
                    270: 		$result=&displayanswers($answer, \@shown, $bubbles_per_line);
                    271: 	    } elsif ( $target eq 'grade') {
                    272: 		&grade_response($answer, \@shown, $bubbles_per_line);
                    273: 	    }  elsif ( $target eq 'analyze') {
                    274: 		my $bubble_lines = &bubble_line_count($answer_count, 
                    275: 						      $bubbles_per_line);
                    276: 		&Apache::response::analyze_store_foilgroup(\@shown,
                    277: 							   ['text','value','location']);
                    278: 		my $part_id="$part.$id";
                    279: 		push (@{ $Apache::lonhomework::analyze{"$part_id.options"} },
                    280: 		      ('true','false'));
                    281: 
                    282: 	    }
                    283: 	}
                    284: 	$Apache::lonxml::post_evaluate=0;
                    285:     }
                    286:     if ($target eq 'web') {
                    287: 	&Apache::response::setup_prior_tries_hash(\&format_prior_answer,
                    288: 						  [\%Apache::response::foilgroup]);
1.114     albertel  289:     }
1.128     foxr      290:     &Apache::response::poprandomnumber();
1.154     raeburn   291:     $bubble_lines = &bubble_line_count($answer_count, $bubbles_per_line);
                    292:     &Apache::lonxml::increment_counter($bubble_lines,
                    293: 				       "$part.$id");
                    294:     if ($target eq 'analyze') {
                    295: 	&Apache::lonhomework::set_bubble_lines();
1.128     foxr      296:     }
1.83      albertel  297:     return $result;
1.6       albertel  298: }
1.151     raeburn   299: sub getbubblesnum {
1.154     raeburn   300:     my ($part,$id) = @_;
1.151     raeburn   301:     my $bubbles_per_line;
                    302:     my $default_numbubbles = $default_bubbles_per_line;
1.154     raeburn   303:     if (($env{'form.bubbles_per_row'} =~ /^\d+$/) &&
                    304:         ($env{'form.bubbles_per_row'} > 0)) {
1.151     raeburn   305:         $default_numbubbles = $env{'form.bubbles_per_row'};
                    306:     }
1.154     raeburn   307:     $bubbles_per_line =
                    308:         &Apache::response::get_response_param($part."_$id",'numbubbles',
                    309:                                               $default_numbubbles);
1.151     raeburn   310:     return $bubbles_per_line;
                    311: }
                    312: 
1.6       albertel  313: sub getfoilcounts {
1.83      albertel  314:     my @names;
1.154     raeburn   315:     my $truecnt=0;
                    316:     my $falsecnt=0;
1.83      albertel  317:     my $name;
                    318:     if ( $Apache::response::foilgroup{'names'} ) {
1.154     raeburn   319: 	@names= @{ $Apache::response::foilgroup{'names'} };
1.6       albertel  320:     }
1.83      albertel  321:     foreach $name (@names) {
1.154     raeburn   322: 	if ($Apache::response::foilgroup{$name.'.value'} eq 'true') {
                    323: 	    $truecnt++;
                    324: 	} elsif ($Apache::response::foilgroup{$name.'.value'} eq 'false') {
                    325: 	    $falsecnt++;
                    326: 	}
1.83      albertel  327:     }
1.154     raeburn   328:     return ($truecnt,$falsecnt);
1.5       albertel  329: }
                    330: 
1.114     albertel  331: sub format_prior_answer {
1.154     raeburn   332:     my ($mode,$answer,$other_data) = @_;
1.114     albertel  333:     my $foil_data = $other_data->[0];
1.154     raeburn   334:     my %response = &Apache::lonnet::str2hash($answer);
                    335:     my ($name)   = keys(%response);
                    336:     return '<span class="LC_prior_radiobutton">'.
                    337: 	$foil_data->{$name.'.text'}.'</span>';
1.114     albertel  338: 
1.112     albertel  339: }
                    340: 
1.120     foxr      341: 
1.155   ! foxr      342: ## 
        !           343: # Return the last survey response.  The logic is slightly different than that of 
        !           344: # get_last_responses.  TODO: See if there are chunks of code betweenthis and
        !           345: # get_last_reponses that are common and can be factored.
        !           346: #
        !           347: # @param $part - Problem part under consideration.
        !           348: # @param $showanswer - True if answers should be shown.
        !           349: # @param $id         - Problem id.
        !           350: #
        !           351: # @return hash reference.
        !           352: # @retval reference to the has indexed by answer selection that 
        !           353: #         indicates the most recent answer.
        !           354: #
        !           355: sub get_last_survey_response {
        !           356:     my ($part, $showanswer, $id) = @_;
        !           357: 
        !           358:     my $newvariation;
        !           359:     my $lastresponse;		# stringified last response.
        !           360: 
        !           361:     if (
        !           362:         (
        !           363:             (
        !           364:                 $Apache::lonhomework::history{"resource.$part.type"} eq
        !           365:                 'randomizetry'
        !           366:             )
        !           367:             || ( $Apache::lonhomework::type eq 'randomizetry' )
        !           368:         )
        !           369:         && ( $Apache::inputtags::status[-1] eq 'CAN_ANSWER' )
        !           370:       )
        !           371:     {
        !           372:         if ( $env{ 'form.' . $part . '.rndseed' } ne
        !           373:             $Apache::lonhomework::history{"resource.$part.rndseed"} )
        !           374:         {
1.147     raeburn   375:             $newvariation = 1;
                    376:         }
                    377:     }
                    378:     $showanswer = &Apache::response::show_answer();
1.155   ! foxr      379:     unless (
        !           380:         (
        !           381:             (
        !           382:                 $Apache::lonhomework::history{"resource.$part.type"} eq
        !           383:                 'anonsurvey'
        !           384:             )
        !           385:             || ( $Apache::lonhomework::history{"resource.$part.type"} eq
        !           386:                 'anonsurveycred' )
        !           387:         )
        !           388:         && ( defined( $env{'form.grade_symb'} ) )
        !           389:         || ( $newvariation && !$showanswer )
        !           390:       )
        !           391:     {
        !           392:         $lastresponse =
        !           393:           $Apache::lonhomework::history{"resource.$part.$id.submission"};
        !           394:     }
        !           395:     my %lastresponse = &Apache::lonnet::str2hash($lastresponse);
        !           396:    
        !           397: 
        !           398:     return \%lastresponse;
        !           399: 
        !           400: }
        !           401: ##
        !           402: # Removes the names from a foil group that are marked as unused.
        !           403: #
        !           404: # @param $names - reference to the array of names to filter.
        !           405: #
        !           406: # @return arrayref
        !           407: # @retval reference to the filtered array.
        !           408: #
        !           409: sub remove_unused {
        !           410:     my ($names) = @_;
        !           411:     my @result;
        !           412: 
        !           413:     foreach my $name (@{$names}) {
        !           414: 	if ($Apache::response::foilgroup{$name . '.value'} ne 'unused') {
        !           415: 	    push(@result, $name);
        !           416: 	}
1.144     raeburn   417:     }
1.155   ! foxr      418:     return \@result;
        !           419: }
        !           420: ## 
        !           421: # Displays all foils in a survey type problem for HTML rendition.
        !           422: # TODO: See if there is any logic in this sub that can be shared
        !           423: #      with display_foils_html
        !           424: #
        !           425: # @param $names        - ref to array of names of the foils to display.
        !           426: # @param $part         - Problem part number.
        !           427: # @param $showanswer   - If true, show the answers.
        !           428: # @param $lastresponse - Ref to the last response hash.
        !           429: # @param $direction    - Display direction of the radiobuttons.
        !           430: #
        !           431: # @return string
        !           432: # @retval HTML required to display the resource in a browser.
        !           433: #
        !           434: sub display_survey_html {
        !           435:     my ($names, $part, $showanswer, $lastresponse, $direction) = @_;
        !           436:     my $result;
        !           437: 
        !           438:     # Figure out a few fragments of html that depend onthe 
        !           439:     # orientation of the radiobuttons:
        !           440:     # closing_html - HTML to emit at the end of the resource.
        !           441:     # pre_foil     - HTML to emit prior to each foil.
        !           442:     # post_foil    - HTML to emit following each foil.
        !           443:     #
        !           444:     #  The opening HTML is just added to the $result now
        !           445:     #
        !           446:     #  Figuring these outin advance compresses the loop over foils into something
        !           447:     #  pretty simple:
        !           448:     #
        !           449:     # NOTE: There's probably a really cool way to do this with style sheets
        !           450:     #       and picking the selector based on the orientation, if someone wants to puzzle
        !           451:     #       that out.  In that case, probably the whole thing lives in a <div> and each
        !           452:     #       foil lives in a <p>
        !           453:     #
        !           454: 
        !           455: 
        !           456:     my ($opening_html, $closing_html, $pre_foil, $post_foil) = 
        !           457: 	&html_direction_fragments($direction);
        !           458: 
        !           459:     $result = $opening_html;
        !           460: 
        !           461:     # Different rendering depending on whether answers are shown:
        !           462:     # I played with different factorings but this seems the most concise/clear...
        !           463:     # although I don't like the $showanswer conditino inside the loop.  Other things I tried
        !           464:     #  - two loops..much longer code..no gain in clarity.
        !           465:     #  - Using a visitor patttern passing it the rendering code chunklets and
        !           466:     #    an anonymous hash reference for state data etc. Very cool but
        !           467:     #    quite a bit more code and quite a bit less clear.
        !           468:     
        !           469:     my $temp = 0;
        !           470:     foreach my $name (@{$names}) {
        !           471: 	$result .= $pre_foil;
        !           472: 
        !           473: 	if ($showanswer) {
        !           474: 	    my $foiltext =  $Apache::response::foilgroup{$name . '.text'};
        !           475: 
        !           476: 	    # Bold the prior  response:
        !           477: 
        !           478: 	    if (defined($lastresponse->{$name})) {
        !           479: 		$result .= '<b>' . $foiltext . '</b>';
        !           480: 	    } else {
        !           481: 		$result .= $foiltext;
1.154     raeburn   482: 	    }
1.155   ! foxr      483: 	} else {
        !           484: 	    $result .= &html_radiobutton(
        !           485: 		$part, $Apache::inputtags::response['-1'], $name, $lastresponse, $temp
        !           486: 	     );
1.154     raeburn   487: 	}
1.155   ! foxr      488: 
        !           489: 	$result .= $post_foil;
        !           490: 	$temp++;
        !           491:     }
        !           492: 
        !           493: 
        !           494:     $result .= $closing_html;
        !           495:     return $result;
        !           496: 
        !           497: }
        !           498: 
        !           499: ##
        !           500: #  Generate LaTeX for surveys.
        !           501: #  
        !           502: #   @param $names - names of the foils to display.
        !           503: #   @param $showanswer - flag that is true to display answers.
        !           504: #   @param $lastresponse - Reference to a hash the indicates the last response.
        !           505: #   @param $direction    - Orientation of foils ('horiztonal' or otherwise).
        !           506: #   @param $venv         - LaTeX name for vertical env.
        !           507: #
        !           508: #   @return string
        !           509: #   @retval LaTeX rendering of the survey question.
        !           510: 
        !           511: sub latex_survey {
        !           512:     my ($names, $showanswer, $lastresponse, $direction, $venv) = @_;
        !           513: 
        !           514:     my $result;
        !           515:     if ($showanswer) {
        !           516: 	$result .= "\\begin{$venv}";
        !           517: 	foreach my $name (@{$names}) {
        !           518: 	    
        !           519: 	    
        !           520: 	    $result .= '\item \vskip -2mm ';
        !           521: 	    
        !           522: 	    if ( defined( $lastresponse->{$name} ) ) {
        !           523: 		$result .= '}';
        !           524: 	    }
        !           525: 	    $result .= $Apache::response::foilgroup{ $name . '.text' } . ' ';
        !           526: 	}
        !           527: 	$result .= "\\end{$venv}";
        !           528: 
        !           529:     } elsif ( $env{'form.pdfFormFields'} eq 'yes'
        !           530: 	      && $Apache::inputtags::status[-1] eq 'CAN_ANSWER') {
        !           531: 	$result .= &display_pdf_form($names, $direction, $venv);
1.154     raeburn   532:     } else {
1.155   ! foxr      533: 	if ($direction eq 'horizontal') {
        !           534: 	    my @foil_texts = &get_foil_texts($names);
        !           535: 	    $result .=  &Apache::caparesponse::make_horizontal_latex_bubbles(
        !           536: 	    $names, \@foil_texts, '$\bigcirc$');
        !           537: 	} else {
        !           538: 	    $result .= "\\begin{$venv}";
        !           539: 
        !           540: 	    my $temp = 0;
        !           541: 	    my $i    = 0;
        !           542: 	    foreach my $name (@{$names}) {
        !           543: 
        !           544: 		$result .= '\item \vskip -2mm ';
        !           545: 		
        !           546: 		if ($env{'form.pdfFormFields'} ne 'yes'
        !           547: 		    or $Apache::inputtags::status[-1] ne 'CAN_ANSWER' )
        !           548: 		{
        !           549: 		    $result .=
        !           550: 			'$\bigcirc$'
        !           551: 			. $Apache::response::foilgroup{ $name . '.text' }
        !           552: 		    . '\\\\';    #' stupid emacs
1.154     raeburn   553: 		}
1.155   ! foxr      554: 		
        !           555: 		$i++;	    
1.154     raeburn   556: 		$temp++;
1.155   ! foxr      557: 		
        !           558: 		$result .= '\vskip 0 mm ';
1.154     raeburn   559: 	    }
1.155   ! foxr      560: 	    $result .= "\\end{$venv}";
        !           561: 	}	
        !           562:     }
        !           563:     return $result;
        !           564: }
        !           565: ##
        !           566: #  Figure out the LaTeX environment in which to wrap the LaTeX vertical output.
        !           567: #
        !           568: # @return string
        !           569: # @retval the environment name.  The LaTeX should be wrapped a 
        !           570: #    \begin{retval} \end{retval} pair.
        !           571: #
        !           572: sub latex_vertical_environment {
        !           573:     if ($env{'form.pdfFormFields'} eq 'yes'
        !           574: 	&& $Apache::inputtags::status[-1] eq 'CAN_ANSWER') {
        !           575: 	return 'itemize';
        !           576:     } else {
        !           577: 	return 'enumerate';
        !           578:     }
        !           579: }
        !           580: 
        !           581: ##
        !           582: # Figure out the key html fragments that depend on the rendering direction:
        !           583: #
        !           584: # @param $direction - 'horizontal' for horizontal direction.
        !           585: #
        !           586: # @return list
        !           587: # @retval (part_start, part_end, foil_start, foil_end)
        !           588: # Where:
        !           589: #   - part_start is the HTML to emit at the start of the part.
        !           590: #   - part_end   is the HTML to emit at the end of the part.
        !           591: #   - foil_start is the HTML to emit prior to each foil.
        !           592: #   - foil_end is the HTML to emit after each foil
        !           593: #
        !           594: sub html_direction_fragments {
        !           595:     my $direction = shift;
        !           596:     if ($direction eq 'horizontal') {
        !           597: 	return ('<table><tr>', '</tr></table>', '<td>', '</td>');
        !           598:     } else {
        !           599: 	return ('', '<br />', '<br />', '');
        !           600:     }
        !           601: }
        !           602: 
        !           603: ##
        !           604: #
        !           605: #  Displays all the foils of a problem in a format suitable for
        !           606: #   surveys, surveys for credit, anonymous surveys and anonymous surveys for credit.
        !           607: #
        !           608: #  @param $direction - Display direction of the choices ('horiztonal' or not).
        !           609: #  @param $target    - Rendering target.
        !           610: #
        !           611: #  @return string
        !           612: #  @retval Text that renders for the selected target.
        !           613: # 
        !           614: sub displayallfoils{
        !           615:     my ( $direction, $target ) = @_;
        !           616:     my $result;
        !           617:     &Apache::lonxml::debug("survey style display");
        !           618: 
        !           619:     my @names;
        !           620: 
        !           621:     if ( $Apache::response::foilgroup{'names'} ) {
        !           622:         @names = @{ $Apache::response::foilgroup{'names'} };
1.45      albertel  623:     }
1.155   ! foxr      624: 
        !           625: 
        !           626:     my $id   = $Apache::inputtags::response['-1'];
        !           627:     my $part = $Apache::inputtags::part;
1.154     raeburn   628:     
1.155   ! foxr      629:     my $showanswer = &Apache::response::show_answer();
        !           630:     my $lastresponse = &get_last_survey_response($part, $showanswer, $id);
        !           631:     my $used_names = &remove_unused(\@names);
        !           632: 
        !           633: 
        !           634:     if ($target ne 'tex') {
        !           635: 	$result .= &display_survey_html(
        !           636: 	    $used_names, $part, $showanswer, $lastresponse, $direction
        !           637: 	);
        !           638:     } else {	
        !           639: 
        !           640: 	my $vertical_env = &latex_vertical_environment();
        !           641: 	$result .= &latex_survey(
        !           642: 	    $used_names, $showanswer, $lastresponse, $direction, $vertical_env
        !           643: 	);
        !           644: 
        !           645:     }
1.83      albertel  646:     return $result;
1.15      albertel  647: }
                    648: 
1.28      albertel  649: sub whichfoils {
1.154     raeburn   650:     my ($max,$randomize)=@_;
1.28      albertel  651: 
1.83      albertel  652:     my @truelist;
                    653:     my @falselist;
1.154     raeburn   654:     my @whichfalse =();
                    655:     my ($truecnt,$falsecnt) = &getfoilcounts();
                    656:     my $count=0;
1.83      albertel  657:     # we will add in 1 of the true statements
1.154     raeburn   658:     if ( $max>0 && ($falsecnt+1)>$max) { $count=$max } else { $count=$falsecnt+1; $max=$count; }
                    659:     my $answer=int(&Math::Random::random_uniform() * ($count));
1.83      albertel  660:     &Apache::lonxml::debug("Count is $count, $answer is $answer");
                    661:     my @names;
                    662:     if ( $Apache::response::foilgroup{'names'} ) {
1.154     raeburn   663: 	@names= @{ $Apache::response::foilgroup{'names'} };
1.83      albertel  664:     }
1.154     raeburn   665:     if (&Apache::response::showallfoils()) {
                    666: 	@whichfalse=@names;
                    667:     } elsif ($randomize eq 'no') {
                    668: 	&Apache::lonxml::debug("No randomization");
                    669: 	my $havetrue=0;
                    670: 	foreach my $name (@names) {
                    671: 	    if ($Apache::response::foilgroup{$name.'.value'} eq 'true') {
                    672: 		if (!$havetrue ) {
                    673: 		    push(@whichfalse,$name); $havetrue++; $answer=$#whichfalse;
                    674: 		}
                    675: 	    } elsif ($Apache::response::foilgroup{$name.'.value'} eq 'false') {
                    676: 		push (@whichfalse,$name);
                    677: 	    } elsif ($Apache::response::foilgroup{$name.'.value'} eq 'unused') {
                    678: 	    } else {
                    679: 		&Apache::lonxml::error(&HTML::Entities::encode("No valid value assigned ($Apache::response::foilgroup{$name.'.value'}) for foil $name in <foilgroup>",'<>&"'));
                    680: 	    }
                    681: 	}
                    682: 	if ((!$havetrue) && 
                    683:             ($Apache::lonhomework::type ne 'survey') && 
                    684:             ($Apache::lonhomework::type ne 'surveycred') &&
                    685:             ($Apache::lonhomework::type ne 'anonsurvey') &&
                    686:             ($Apache::lonhomework::type ne 'anonsurveycred')) {
                    687: 	    &Apache::lonxml::error(&mt('There are no true statements available.').'<br />');
                    688: 	}
                    689:     } else {
                    690: 	my $current=0;
                    691: 	&Apache::lonhomework::showhash(%Apache::response::foilgroup);
                    692: 	my (%top,%bottom);
                    693: 	#first find out where everyone wants to be
                    694: 	foreach my $name (@names) {
                    695: 	    $current++;
                    696: 	    if ($Apache::response::foilgroup{$name.'.value'} eq 'true') {
                    697: 		push (@truelist,$name);
                    698: 		if ($Apache::response::foilgroup{$name.'.location'} eq 'top') {
                    699: 		    $top{$name}=$current;
                    700: 		} elsif ($Apache::response::foilgroup{$name.'.location'} eq 'bottom') {
                    701: 		    $bottom{$name}=$current;
                    702: 		}
                    703: 	    } elsif ($Apache::response::foilgroup{$name.'.value'} eq 'false') {
                    704: 		push (@falselist,$name);
                    705: 		if ($Apache::response::foilgroup{$name.'.location'} eq 'top') {
                    706: 		    $top{$name}=$current;
                    707: 		} elsif ($Apache::response::foilgroup{$name.'.location'} eq 'bottom') {
                    708: 		    $bottom{$name}=$current;
                    709: 		}
                    710: 	    } elsif ($Apache::response::foilgroup{$name.'.value'} eq 'unused') {
                    711: 	    } else {
                    712: 		&Apache::lonxml::error(&HTML::Entities::encode("No valid value assigned ($Apache::response::foilgroup{$name.'.value'}) for foil $name in <foilgroup>",'<>&"'));
                    713: 	    }
                    714: 	}
                    715: 	#pick a true statement
                    716: 	my $notrue=0;
                    717: 	if (scalar(@truelist) == 0) { $notrue=1; }
                    718: 	my $whichtrue = int(&Math::Random::random_uniform() * ($#truelist+1));
                    719: 	&Apache::lonxml::debug("Max is $max, From $#truelist elms, picking $whichtrue");
                    720: 	my (@toplist, @bottomlist);
                    721: 	my $topcount=0;
                    722: 	my $bottomcount=0;
                    723: 	# assign everyone to either toplist/bottomlist or whichfalse
                    724: 	# which false is randomized, toplist bottomlist are in order
                    725: 	while ((($#whichfalse+$topcount+$bottomcount) < $max-2) && ($#falselist > -1)) {
                    726: 	    &Apache::lonxml::debug("Have $#whichfalse max is $max");
                    727: 	    my $afalse=int(&Math::Random::random_uniform() * ($#falselist+1));
                    728: 	    &Apache::lonxml::debug("From $#falselist elms, picking $afalse");
                    729: 	    $afalse=splice(@falselist,$afalse,1);
                    730: 	    &Apache::lonxml::debug("Picked $afalse");
                    731: 	    &Apache::lonhomework::showhash(('names'=>\@names));
                    732: 	    &Apache::lonhomework::showhash(%top);
                    733: 	    if ($top{$afalse}) {
                    734: 		$toplist[$top{$afalse}]=$afalse;
                    735: 		$topcount++;
                    736: 	    } elsif ($bottom{$afalse}) {
                    737: 		$bottomlist[$bottom{$afalse}]=$afalse;
                    738: 		$bottomcount++;
                    739: 	    } else {
                    740: 		push (@whichfalse,$afalse);
                    741: 	    }
                    742: 	}
                    743: 	&Apache::lonxml::debug("Answer wants $answer");
                    744: 	my $truename=$truelist[$whichtrue];
                    745: 	my $dosplice=1;
                    746: 	if (($notrue) && 
                    747:             ($Apache::lonhomework::type ne 'survey') &&
                    748:             ($Apache::lonhomework::type ne 'surveycred') &&
                    749:             ($Apache::lonhomework::type ne 'anonsurvey') &&
                    750:             ($Apache::lonhomework::type ne 'anonsurveycred')) {
                    751: 	    $dosplice=0;
                    752: 	    &Apache::lonxml::error(&mt('There are no true statements available.').'<br />');
                    753: 	}
                    754: 	#insert the true statement, keeping track of where it wants to be
                    755: 	if ($Apache::response::foilgroup{$truename.'.location'} eq 'top' && $dosplice) {
                    756: 	    $toplist[$top{$truename}]=$truename;
                    757: 	    $answer=-1;
                    758: 	    foreach my $top (reverse(@toplist)) {
                    759: 		if ($top) { $answer++;}
                    760: 		if ($top eq $truename) { last; }
                    761: 	    }
                    762: 	    $dosplice=0;
                    763: 	} elsif ($Apache::response::foilgroup{$truename.'.location'} eq 'bottom' && $dosplice) {
                    764: 	    $bottomlist[$bottom{$truename}]=$truename;
                    765: 	    $answer=-1;
                    766: 	    foreach my $bot (@bottomlist) {
                    767: 		if ($bot) { $answer++;}
                    768: 		if ($bot eq $truename) { last; }
                    769: 	    }
                    770: 	    $answer+=$topcount+$#whichfalse+1;
                    771: 	    $dosplice=0;
                    772: 	} else {
                    773: 	    if ($topcount>0 || $bottomcount>0) {
1.150     raeburn   774:                 my $inc = 1;
1.154     raeburn   775:                 if (($bottomcount > 0) && ($Apache::lonhomework::type ne 'exam')) {
1.150     raeburn   776:                     $inc = 2;
                    777:                 }
1.154     raeburn   778:                 $answer=int(&Math::Random::random_uniform() * ($#whichfalse+$inc))
                    779:                         + $topcount;
                    780: 	    }
                    781: 	}
                    782: 	&Apache::lonxml::debug("Answer now wants $answer");
                    783: 	#add the top items to the top, bottom items to the bottom
                    784: 	for (my $i=0;$i<=$#toplist;$i++) {
                    785: 	    if ($toplist[$i]) { unshift(@whichfalse,$toplist[$i]) }
                    786: 	}
                    787: 	for (my $i=0;$i<=$#bottomlist;$i++) {
                    788: 	    if ($bottomlist[$i]) { push(@whichfalse,$bottomlist[$i]) }
                    789: 	}
                    790: 	#if the true statement is randomized insert it into the list
                    791: 	if ($dosplice) { splice(@whichfalse,$answer,0,$truelist[$whichtrue]); }
1.49      albertel  792:     }
1.83      albertel  793:     &Apache::lonxml::debug("Answer is $answer");
1.154     raeburn   794:     return ($answer,@whichfalse);
1.28      albertel  795: }
                    796: 
1.155   ! foxr      797: ## 
        !           798: #  Return a list  of foil texts given foil names.
        !           799: #  
        !           800: # @param $whichfoils - Reference to a list of foil names.
        !           801: #
        !           802: # @return array
        !           803: # @retval foil texts
        !           804: #
        !           805: sub get_foil_texts {
        !           806:     my ($whichfoils) = @_;
        !           807:     my @foil_texts;
        !           808: 
        !           809:     foreach my $name (@{$whichfoils}) {
        !           810: 	push(@foil_texts, $Apache::response::foilgroup{$name . '.text'});
        !           811:     }
        !           812:     return @foil_texts;
        !           813: }
        !           814: 
        !           815: ##
        !           816: # Generate the HTML for a single html foil.
        !           817: # @param $part           - The part for which the response is being generated.
        !           818: # @param $fieldname      - The basename of the radiobutton field
        !           819: # @param $name           - The foilname.
        !           820: # @param $last_responses - Reference to a hash that holds the most recent
        !           821: #                          responses.
        !           822: # @param $value          - radiobutton value.
        !           823: # 
        !           824: # @return text
        !           825: # @retval The generated html.
        !           826: #
        !           827: sub html_radiobutton {
        !           828:     my ($part, $fieldname, $name, $last_responses, $value) = @_;
        !           829: 
        !           830:     my $result='<label>';
        !           831:     
        !           832:     $result .= '<input type="radio"
        !           833:                 onchange="javascript:setSubmittedPart(' . "'$part');\""
        !           834: 		. 'name="HWVAL_' . $fieldname . '"'
        !           835: 		. "value='$value'";
        !           836: 
        !           837:     if (defined($last_responses->{$name})) {
        !           838: 	$result .= '  checked="checked" ';
        !           839:     }
        !           840:     $result .= ' />';
        !           841:     $result .= $Apache::response::foilgroup{$name . '.text'};
        !           842:     $result .= '</label>';
        !           843: 
        !           844:     return $result;
        !           845: 
        !           846: }
        !           847: ##
        !           848: # Return a reference to the last response hash. This hash has exactly
        !           849: # one or zero entries.  The one entry is keyed by the foil 'name' of
        !           850: # the prior response
        !           851: #
        !           852: # @param $part - Number of the problem part.
        !           853: # 
        !           854: # @return reference to a hash.
        !           855: # @retval see above.
        !           856: #
        !           857: sub get_last_response {
        !           858:     my ($part) = @_;
        !           859: 
        !           860:     my $id = $Apache::inputtags::response['-1'];
        !           861:     my ( $lastresponse, $newvariation );
        !           862:     
        !           863:     if ((( $Apache::lonhomework::history{"resource.$part.type"} eq  'randomizetry')
        !           864: 	 || ( $Apache::lonhomework::type eq 'randomizetry' )
        !           865: 	)
        !           866: 	&& ( $Apache::inputtags::status[-1] eq 'CAN_ANSWER' )
        !           867: 	)
        !           868:     {
        !           869: 	
        !           870: 	if ( $env{ 'form.' . $part . '.rndseed' } ne
        !           871: 	     $Apache::lonhomework::history{"resource.$part.rndseed"} )
        !           872: 	{
        !           873: 	    $newvariation = 1;
        !           874: 	}
        !           875:     }
        !           876:     unless ($newvariation) {
        !           877: 	$lastresponse =
        !           878: 	    $Apache::lonhomework::history{"resource.$part.$id.submission"};
        !           879:     }
        !           880:     my %lastresponse = &Apache::lonnet::str2hash($lastresponse);
        !           881: 
        !           882:     return \%lastresponse;
        !           883: }
        !           884: 
        !           885: ##
        !           886: # Display foils in html rendition.:
        !           887: #
        !           888: # @param $whichfoils - Set of foils to display.
        !           889: # @param $target     - Rendition target...there are several html targets.
        !           890: # @param $direction  - 'horizontal' if layout is horizontal.
        !           891: # @param $part       - Part of the problem that's being displayed.
        !           892: # @param $show_answer- True if answers should be shown.
        !           893: #
        !           894: # @return string
        !           895: # @retval generated html.
        !           896: #
        !           897: sub display_foils_html {
        !           898:     my ($whichfoils, $target, $direction, $part, $show_answer) = @_;
1.83      albertel  899:     my $result;
1.28      albertel  900: 
1.155   ! foxr      901: 
        !           902:     # if the answers get shown, we need to label each item as correct or
        !           903:     # incorrect.
        !           904: 
        !           905:     my ($opening_html, $finalclose, $item_pretext, $item_posttext) = 
        !           906: 	&html_direction_fragments($direction);
        !           907: 
        !           908:     $result .= $opening_html;
        !           909: 
        !           910: 
        !           911:     if ($show_answer) {
        !           912: 
        !           913: 	foreach my $name (@{$whichfoils}) {
        !           914: 
        !           915: 	    # If the item gets further surrounded by tags, this 
        !           916: 	    # holds the closures for those tages.
        !           917: 
        !           918: 	    my $item_closetag = '';
        !           919: 
        !           920: 	    $result .= $item_pretext;
        !           921: 
        !           922: 	    # Label each foil as correct or incorrect:
        !           923: 
        !           924: 	    if ($Apache::response::foilgroup{$name . '.value'} eq 'true') {
        !           925: 		$result .= &mt('Correct:') . '<b>';
        !           926: 		$item_closetag .= '</b>';
        !           927: 		
1.154     raeburn   928: 	    } else {
1.155   ! foxr      929: 		$result .= &mt('Incorrect');
1.154     raeburn   930: 	    }
1.155   ! foxr      931: 
        !           932: 	    # Web rendition encloses the 
        !           933: 	    # item text in a label tag as well:
        !           934: 
        !           935: 	    if ($target eq 'web') {
        !           936: 		$result .= '<label>';
        !           937: 		$item_closetag = '</label>' . $item_closetag;
1.154     raeburn   938: 	    }
1.155   ! foxr      939: 	    $result .= $Apache::response::foilgroup{$name . '.text'};
        !           940: 	    $result .= $item_closetag;
        !           941: 	    $result .= $item_posttext;
        !           942: 	    $result .= "\n";	# make the html a bit more readable.
        !           943: 	}
        !           944: 
        !           945: 
        !           946:     } else {
        !           947: 	my $lastresponse = &get_last_response($part);
        !           948: 	
        !           949: 	my $item_no = 0;
        !           950: 	foreach my $name (@{$whichfoils}) {
        !           951: 	    $result .= $item_pretext;
        !           952: 	    $result .= &html_radiobutton(
        !           953: 		$part, $Apache::inputtags::response[-1],
        !           954: 		$name, $lastresponse, $item_no
        !           955: 		);
        !           956: 	    $result .= $item_posttext;
        !           957: 	    $item_no++;
        !           958: 	}
        !           959: 	
        !           960:     }
        !           961:     $result .= $finalclose;
        !           962: 
        !           963:     return $result;
        !           964: }
        !           965: ##
        !           966: #  Display foils in exam mode for latex
        !           967: #
        !           968: # @param $whichfoils       - Reference to an array that contains the foil names to display
        !           969: # @param $bubbles_per_line - Number of bubbles on a line.
        !           970: # @param $direction        - Rendering direction 'horizontal' is what we're looking for.
        !           971: # @param $venv             - Name of LaTeX environment to use for vertical rendering.
        !           972: #
        !           973: # @return string
        !           974: # @return the latex rendering of the exam problem.
        !           975: #
        !           976: #
        !           977: sub display_latex_exam {
        !           978:     my ($whichfoils, $bubbles_per_line, $direction, $venv) = @_;
        !           979:     my $result;
        !           980:     my $numlines;
        !           981:     my $bubble_number = 0;
        !           982:     my $line          = 0;
        !           983:     my $i             = 0;
        !           984: 
        !           985:     
        !           986:     if ($direction eq  'horizontal') {
        !           987: 
        !           988: 	# Marshall the display text for each foil and turn things over to
        !           989: 	# Apache::response::make_horizontal_bubbles:
        !           990: 
        !           991: 	my @foil_texts = &get_foil_texts($whichfoils);
        !           992: 	$result .= &Apache::caparesponse::make_horizontal_latex_bubbles(
        !           993: 	    $whichfoils, \@foil_texts, '$\bigcirc$');
        !           994: 
        !           995:     } else {
        !           996: 	
        !           997: 	$result .= '\vskip 2mm \noindent';
        !           998: 
        !           999: 	# This section puts out the prefix that tells the user
        !          1000: 	# (if necessary) to only choose one bubble in the next n lines
        !          1001: 	# for problems with more than one line worth of bubbles in the grid sheet:
        !          1002: 	
        !          1003: 	my $numitems = scalar( @{$whichfoils} );
        !          1004: 	$numlines = int( $numitems / $bubbles_per_line );
        !          1005: 	if ( ( $numitems % $bubbles_per_line ) != 0 ) {
        !          1006: 	    $numlines++;
        !          1007: 	}
        !          1008: 	if ( $numlines < 1 ) {
        !          1009: 	    $numlines = 1;
        !          1010: 	}
        !          1011: 	if ( $numlines > 1 ) {
        !          1012: 	    my $linetext;
        !          1013: 	    for ( my $i = 0 ; $i < $numlines ; $i++ ) {
        !          1014: 		$linetext .= $Apache::lonxml::counter + $i . ', ';
        !          1015: 	    }
        !          1016: 	    $linetext =~ s/,\s$//;
        !          1017: 	    $result .=
        !          1018: 		'\small {\textbf{'
        !          1019: 		. $linetext . '}} '
        !          1020: 		. ' {\footnotesize '
        !          1021: 		. &mt( '(Bubble once in [_1] lines)', $numlines )
        !          1022: 		. '} \hspace*{\fill} \\\\';
        !          1023: 	}
        !          1024: 	else {
        !          1025: 	    $result .= '\textbf{' . $Apache::lonxml::counter . '}.';
        !          1026: 	}
        !          1027: 	
        !          1028: 	# Now output the bubbles themselves:
        !          1029: 	
        !          1030: 	foreach my $name (@{$whichfoils}) {
        !          1031: 	    if ( $bubble_number >= $bubbles_per_line ) {
        !          1032: 		$line++;
        !          1033: 		$i             = 0;
        !          1034: 		$bubble_number = 0;
        !          1035: 	    }
        !          1036: 	    my $identifier;
        !          1037: 	    if ( $numlines > 1 ) {
        !          1038: 		$identifier = $Apache::lonxml::counter + $line;
        !          1039: 	    }
        !          1040: 	    my $preindent;
        !          1041: 	    if ($bubble_number > 0) {
        !          1042: 		$preindent = '\hspace*{3 mm}';
        !          1043: 	    }
        !          1044: 	    my $foiltext = $Apache::response::foilgroup{$name . '.text'};
        !          1045: 	    $foiltext =~ s/\\noindent//; # forgive me for I have sinned..
        !          1046: 	    $result .= '{\small \textbf{'
        !          1047: 		. $identifier  .$preindent
        !          1048: 		. $alphabet[$i]
        !          1049: 		. '}}$\bigcirc$'
        !          1050: 		. $foiltext
        !          1051: 	    . '\\\\';    #' stupid emacs -- it thinks it needs that apostrophe to close the quote
        !          1052: 	    
        !          1053: 	    $i++;
        !          1054: 	    $bubble_number++;
1.154     raeburn  1055: 	}
1.155   ! foxr     1056: 
        !          1057:     }	
        !          1058: 
        !          1059:     return $result;
        !          1060:     
        !          1061: }
        !          1062: 
        !          1063: ##
        !          1064: #  Display latex when exam mode is not on.
        !          1065: #
        !          1066: #  @param $whichfoils - The foils to display
        !          1067: #  @param $direction  - Display direction ('horizontal' is what matters to us).
        !          1068: #  @param $venv       - Vertical env. to use for vertical rendering.
        !          1069: #  @param  $vend      - End the vertical environment being used.
        !          1070: #
        !          1071: #  @return string
        !          1072: #  @retval - The LaTeX rendering of the resource.'
        !          1073: #
        !          1074: sub display_latex {
        !          1075:     my ($whichfoils, $direction, $venv) = @_;
        !          1076:     my $result;
        !          1077: 
        !          1078:     # how we render depends on the direction.
        !          1079:     # Vertical is some kind of list environment determined by vbegin/vend.
        !          1080:     # Horizontal is a table that is generated by 
        !          1081:     # Apache::caparesponse::make_horizontal_latex_bubbles with an empty string
        !          1082:     # for the actual bubble text.
        !          1083: 
        !          1084:     if ($direction eq 'horizontal') {
        !          1085: 	my @foil_texts = &get_foil_texts($whichfoils);
        !          1086: 	$result .= &Apache::caparesponse::make_horizontal_latex_bubbles(
        !          1087: 	    $whichfoils, \@foil_texts, '');
        !          1088:     } else {
        !          1089: 	$result .= "\\begin{$venv}";
        !          1090: 	foreach my $name (@{$whichfoils}) {
        !          1091: 	    $result .=  '\vspace*{-2 mm}\item '
        !          1092: 		. $Apache::response::foilgroup{ $name . '.text' };
1.154     raeburn  1093: 	}
1.155   ! foxr     1094: 	
        !          1095: 	$result .= "\\end{$venv}";
        !          1096:     }
        !          1097:     return $result;
        !          1098: }
        !          1099: 
        !          1100: 
        !          1101: ##
        !          1102: #  Render foils for a PDF form. This is a variant of tex rednering that provides
        !          1103: #  sufficient markup that the final PDF is a form that can be filled in online,
        !          1104: #  or offline.
        !          1105: #
        !          1106: # @param $whichfoils - References an array of foils to display in the order in which
        !          1107: #                     they should be displayed.
        !          1108: # @param $direction  - Rendering direction.  'horiztonal' means inputs are laid out
        !          1109: #                      horizontally otherwise they are stacked vertically.
        !          1110: # @param $venv       - Vertical environment in which to wrap the foils.
        !          1111: #
        !          1112: # @return string
        !          1113: # @retval String containing the rendering of the resource.
        !          1114: #
        !          1115: # TODO: Take into account direction!!!
        !          1116: #
        !          1117: sub display_pdf_form {
        !          1118:     my ($whichfoils, $direction, $venv) = @_;
        !          1119:     my $temp = 0;
        !          1120:     my $result;
        !          1121: 
        !          1122:     $result .= "\\begin{$venv}";
        !          1123:     foreach my $name ( @{$whichfoils} ) {
        !          1124: 	
        !          1125: 	my $fieldname =
        !          1126: 	    $env{'request.symb'} 
        !          1127: 	. '&part_'
        !          1128: 	    . $Apache::inputtags::part
        !          1129: 	    . '&radiobuttonresponse'
        !          1130: 	    . '&HWVAL_'
        !          1131: 	    . $Apache::inputtags::response['-1'];
        !          1132: 	$result .= '\item[{'
        !          1133: 	    . &Apache::lonxml::print_pdf_radiobutton( $fieldname,
        !          1134: 						      $temp )
        !          1135: 	    . '}]'
        !          1136: 	    . $Apache::response::foilgroup{ $name . '.text' }
        !          1137: 	. "\n";
        !          1138: 	
        !          1139: 	$temp++;
        !          1140:     }
        !          1141:     $result .= "\\end{$venv}";
        !          1142: 
        !          1143:     return $result;
        !          1144: }
        !          1145: 
        !          1146: 
        !          1147: ##
        !          1148: # Display selected foils:  This is really just a dispatchter to appropriate renderers
        !          1149: #  
        !          1150: # @param $target   - Target (e.g. 'tex'...).
        !          1151: # @param $answer   - True if answers should be shown.
        !          1152: # @param $whichfoils - Array of foil selectors that indicate which foils shouild be
        !          1153: #                      rendered, in rendering order.
        !          1154: # @param $direction- Rendering direction ('horizontal' is the one we look for,
        !          1155: #                    otherwise foils are rendered one per line vertically.
        !          1156: # @param $bubbles_per_line - number of exam bubbles per line.
        !          1157: #
        !          1158: # @return string
        !          1159: # @retval The rendered problem.
        !          1160: 
        !          1161: sub displayfoils {
        !          1162:     my ($target,$answer,$whichfoils,$direction, $bubbles_per_line)=@_;
        !          1163:     my $result;
        !          1164: 
        !          1165: 
        !          1166:     my $part   = $Apache::inputtags::part;
        !          1167:     my $solved = $Apache::lonhomework::history{"resource.$part.solved"};
        !          1168: 
        !          1169:     # Show answers html.
        !          1170: 
        !          1171:     if ( ( $target ne 'tex' )
        !          1172:         && &Apache::response::show_answer() )
        !          1173:     {
        !          1174: 
        !          1175: 	$result = &display_foils_html(
        !          1176: 	    $whichfoils, $target, $direction, $part,  1);
        !          1177: 	
        !          1178: 	# other html
        !          1179:     }  elsif ($target ne 'tex') {
        !          1180: 	    $result = &display_foils_html($whichfoils, $target, $direction, $part,
        !          1181: 					  0, 0);
        !          1182: 
        !          1183:        # LaTeX rendering:
1.154     raeburn  1184:     } else {
1.155   ! foxr     1185: 
        !          1186: 
        !          1187:         my $id            = $Apache::inputtags::response['-1'];
        !          1188:         my $part          = $Apache::inputtags::part;
        !          1189: 	my $numlines;
        !          1190: 	
        !          1191: 	# Decide how to bracket the list of foils:
        !          1192: 
        !          1193: 	my $vertical_env = &latex_vertical_environment();
        !          1194: 
        !          1195: 	# Rendering for latex exams.
        !          1196: 	
        !          1197: 	if ( ( $Apache::lonhomework::type eq 'exam' ) )
        !          1198: 	{
        !          1199: 	    $result .= &display_latex_exam(
        !          1200: 		$whichfoils, $bubbles_per_line, $direction, $vertical_env);
        !          1201: 
        !          1202: 	    $result .= '\vskip 0mm ';
        !          1203: 	    
        !          1204: 	} else {	    
        !          1205: 
        !          1206: 	    # Different rendering for PDF form than for a
        !          1207: 	    # 'regular' answer direction is honored in both of those
        !          1208: 	    #
        !          1209: 
        !          1210: 	    if ( ($env{'form.pdfFormFields'} eq 'yes')
        !          1211: 		    && ($Apache::inputtags::status[-1] eq 'CAN_ANSWER'))
        !          1212: 	    {
        !          1213: 		$result .= &display_pdf_form($whichfoils, $direction, $vertical_env);
1.154     raeburn  1214: 	    } else {
1.155   ! foxr     1215: 		$result .= &display_latex($whichfoils,  $direction, $vertical_env );
1.154     raeburn  1216: 	    }
1.155   ! foxr     1217: 	    $result .= '\vskip 0 mm '; 
        !          1218:        
1.154     raeburn  1219: 	}
1.83      albertel 1220:     }
                   1221:     return $result;
1.81      albertel 1222: }
                   1223: 
                   1224: sub displayallanswers {
1.106     albertel 1225:     my @names;
                   1226:     if ( $Apache::response::foilgroup{'names'} ) {
1.154     raeburn  1227: 	@names= @{ $Apache::response::foilgroup{'names'} };
1.106     albertel 1228:     }
1.154     raeburn  1229:     my $result=&Apache::response::answer_header('radiobuttonresponse');
1.81      albertel 1230:     foreach my $name (@names) {
1.154     raeburn  1231: 	$result.=&Apache::response::answer_part('radiobuttonresponse',
                   1232: 				$Apache::response::foilgroup{$name.'.value'});
1.81      albertel 1233:     }
1.154     raeburn  1234:     $result.=&Apache::response::answer_footer('radiobuttonresponse');
1.81      albertel 1235:     return $result;
1.14      albertel 1236: }
                   1237: 
1.28      albertel 1238: sub displayanswers {
1.154     raeburn  1239:     my ($answer, $whichopt, $bubbles_per_line)=@_;
1.124     albertel 1240:     my $result;
                   1241: 
1.154     raeburn  1242:     if ($Apache::lonhomework::type eq 'exam') {
                   1243: 	my $line = int($answer/$bubbles_per_line);
                   1244: 	my $correct = ('A'..'Z')[$answer%$bubbles_per_line];
                   1245: 	$result .= &Apache::response::answer_header('radiobuttonresponse',
                   1246: 						    $line);
                   1247: 	$result .= &Apache::response::answer_part('radiobuttonresponse',
                   1248: 						  $correct);
                   1249:     } else {
                   1250: 	$result .= &Apache::response::answer_header('radiobuttonresponse');
                   1251:     }
                   1252:     foreach my $name (@{ $whichopt }) {
                   1253: 	$result.=&Apache::response::answer_part('radiobuttonresponse',
                   1254: 						$Apache::response::foilgroup{$name.'.value'});
1.105     albertel 1255:     }
1.154     raeburn  1256:     $result.=&Apache::response::answer_footer('radiobuttonresponse');
1.83      albertel 1257:     return $result;
1.28      albertel 1258: }
                   1259: 
1.14      albertel 1260: sub start_conceptgroup {
1.154     raeburn  1261:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   1262:     $Apache::radiobuttonresponse::conceptgroup=1;
                   1263:     %Apache::response::conceptgroup=();
1.83      albertel 1264:     my $result;
1.154     raeburn  1265:     if ($target eq 'edit') {
                   1266: 	$result.=&Apache::edit::tag_start($target,$token);
                   1267: 	$result.=&Apache::edit::text_arg('Concept:','concept',$token,'50').
                   1268: 	    &Apache::edit::end_row().&Apache::edit::start_spanning_row();
                   1269:     } elsif ($target eq 'modified') {
                   1270: 	my $constructtag=&Apache::edit::get_new_args($token,$parstack,
                   1271: 						     $safeeval,'concept');
                   1272: 	if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); }
1.83      albertel 1273:     }
                   1274:     return $result;
1.14      albertel 1275: }
                   1276: 
                   1277: sub end_conceptgroup {
1.154     raeburn  1278:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   1279:     $Apache::radiobuttonresponse::conceptgroup=0;
1.83      albertel 1280:     my $result;
1.154     raeburn  1281:     if ($target eq 'web' || $target eq 'grade' || $target eq 'answer'  ||
                   1282: 	$target eq 'tex' || $target eq 'analyze') {
                   1283: 	&Apache::response::pick_foil_for_concept($target,
                   1284: 						 ['value','text','location'],
                   1285: 						 \%Apache::hint::radiobutton,
                   1286: 						 $parstack,$safeeval);
                   1287:     } elsif ($target eq 'edit') {
                   1288: 	$result=&Apache::edit::end_table();
1.83      albertel 1289:     }
                   1290:     return $result;
1.26      albertel 1291: }
                   1292: 
                   1293: sub insert_conceptgroup {
1.154     raeburn  1294:     my $result="\n\t\t<conceptgroup concept=\"\">".&insert_foil()."\n\t\t</conceptgroup>\n";
1.83      albertel 1295:     return $result;
1.1       albertel 1296: }
                   1297: 
                   1298: sub start_foil {
1.154     raeburn  1299:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   1300:     my $result='';
                   1301:     if ($target eq 'web' || $target eq 'tex' || $target eq 'analyze') {
                   1302: 	&Apache::lonxml::startredirection;
                   1303: 	if ($target eq 'analyze') {
                   1304: 	    &Apache::response::check_if_computed($token,$parstack,$safeeval,'value');
                   1305: 	}
                   1306:     } elsif ($target eq 'edit') {
                   1307: 	$result=&Apache::edit::tag_start($target,$token);
                   1308: 	$result.=&Apache::edit::text_arg('Name:','name',$token);
                   1309: 	$result.=&Apache::edit::select_or_text_arg('Correct Option:','value',
                   1310: 						   ['unused','true','false'],
                   1311: 						   $token);
                   1312: 	my $randomize=&Apache::lonxml::get_param('randomize',$parstack,
                   1313: 						 $safeeval,'-3');
                   1314: 	if ($randomize ne 'no') {
                   1315: 	    $result.=&Apache::edit::select_arg('Location:','location',
                   1316: 					       ['random','top','bottom'],$token);
                   1317: 	}
                   1318: 	$result.=&Apache::edit::end_row().&Apache::edit::start_spanning_row();
                   1319:     } elsif ($target eq 'modified') {
                   1320: 	my $constructtag=&Apache::edit::get_new_args($token,$parstack,
                   1321: 						     $safeeval,'value','name',
                   1322: 						     'location');
                   1323: 	if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); }
                   1324:     } 
1.83      albertel 1325:     return $result;
1.1       albertel 1326: }
                   1327: 
                   1328: sub end_foil {
1.154     raeburn  1329:     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
                   1330:     my $text='';
                   1331:     if ($target eq 'web' || $target eq 'tex' || $target eq 'analyze') {
                   1332: 	$text=&Apache::lonxml::endredirection;
                   1333:     }
                   1334:     if ($target eq 'web' || $target eq 'grade' || $target eq 'answer'
                   1335: 	|| $target eq 'tex' || $target eq 'analyze') {
                   1336: 	my $value = &Apache::lonxml::get_param('value',$parstack,$safeeval);
                   1337: 	if ($value ne 'unused') {
                   1338: 	    my $name = &Apache::lonxml::get_param('name',$parstack,$safeeval);
                   1339: 	    if ($name eq "") {
                   1340: 		&Apache::lonxml::warning(&mt('Foils without names exist. This can cause problems to malfunction.'));
                   1341: 		$name=$Apache::lonxml::curdepth;
                   1342: 	    }
                   1343: 	    if (defined($Apache::response::foilnames{$name})) {
                   1344: 		&Apache::lonxml::error(&mt('Foil name [_1] appears more than once. Foil names need to be unique.','<b><tt>'.$name.'</tt></b>'));
                   1345: 	    }
                   1346: 	    $Apache::response::foilnames{$name}++;
                   1347: 	    my $location =&Apache::lonxml::get_param('location',$parstack,
                   1348: 						     $safeeval);
                   1349: 	    if ( $Apache::radiobuttonresponse::conceptgroup
                   1350: 		 && !&Apache::response::showallfoils() ) {
                   1351: 		push @{ $Apache::response::conceptgroup{'names'} }, $name;
                   1352: 		$Apache::response::conceptgroup{"$name.value"} = $value;
                   1353: 		$Apache::response::conceptgroup{"$name.text"} = $text;	
                   1354: 		$Apache::response::conceptgroup{"$name.location"} = $location;
                   1355: 	    } else {
                   1356: 		push @{ $Apache::response::foilgroup{'names'} }, $name;
                   1357: 		$Apache::response::foilgroup{"$name.value"} = $value;
                   1358: 		$Apache::response::foilgroup{"$name.text"} = $text;
                   1359: 		$Apache::response::foilgroup{"$name.location"} = $location;
                   1360: 	    }
                   1361: 	}
1.18      albertel 1362:     }
1.83      albertel 1363:     return '';
1.1       albertel 1364: }
                   1365: 
1.27      albertel 1366: sub insert_foil {
1.83      albertel 1367:     return '
1.27      albertel 1368: <foil name="" value="unused">
                   1369: <startouttext />
                   1370: <endouttext />
                   1371: </foil>';
                   1372: }
1.151     raeburn  1373: 
1.1       albertel 1374: 1;
                   1375: __END__
1.139     jms      1376: 
                   1377: 
                   1378: 
                   1379: =head1 NAME
                   1380: 
                   1381: Apache::radiobuttonresponse
                   1382: 
                   1383: =head1 SYNOPSIS
                   1384: 
                   1385: Handles multiple-choice style responses.
                   1386: 
                   1387: This is part of the LearningOnline Network with CAPA project
                   1388: described at http://www.lon-capa.org.
                   1389: 
                   1390: =head1 SUBROUTINES
                   1391: 
                   1392: =over
                   1393: 
                   1394: =item start_radiobuttonresponse()
                   1395: 
                   1396: =item bubble_line_count()
                   1397: 
                   1398: =item end_radiobuttonresponse()
                   1399: 
                   1400: =item start_foilgroup()
                   1401: 
                   1402: =item storesurvey()
                   1403: 
                   1404: =item grade_response()
                   1405: 
                   1406: =item end_foilgroup()
                   1407: 
                   1408: =item getfoilcounts()
                   1409: 
                   1410: =item format_prior_answer()
                   1411: 
                   1412: =item displayallfoils()
                   1413: 
                   1414: =item &whichfoils($max,$randomize)
                   1415: 
                   1416: Randomizes the list of foils.
                   1417: Respects
                   1418:   - each foils desire to be randomized
                   1419:   - the existance of Concept groups of foils (select 1 foil from each)
                   1420:   - and selects a single correct statement from all possilble true statments
                   1421:   - and limits it to a toal of $max foils
                   1422: 
                   1423: WARNING: this routine uses the random number generator, it should only
                   1424: be called once per target, otherwise it can cause randomness changes in
                   1425: homework problems.
                   1426: 
                   1427: Arguments
                   1428:   $max - maximum number of foils to select (including the true one)
                   1429:          (so a max of 5 is: 1 true, 4 false)
                   1430: 
                   1431:   $randomize - whether to randomize the listing of foils, by default
                   1432:                will randomize, only if randomize is 'no' will it not
                   1433: 
                   1434: Returns
                   1435:   $answer - location in the array of the correct answer
                   1436:   @foils  - array of foil names in to display order
                   1437: 
                   1438: =item displayfoils()
                   1439: 
                   1440: =item displayallanswers()
                   1441: 
                   1442: =item displayanswers()
                   1443: 
                   1444: =item start_conceptgroup()
                   1445: 
                   1446: =item end_conceptgroup()
                   1447: 
                   1448: =item insert_conceptgroup()
                   1449: 
                   1450: =item start_foil()
                   1451: 
                   1452: =item end_foil()
                   1453: 
                   1454: =item insert_foil()
                   1455: 
                   1456: =back
                   1457: 
                   1458: =cut
1.1       albertel 1459:  

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>
500 Internal Server Error

Internal Server Error

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.