File:  [LON-CAPA] / loncom / homework / radiobuttonresponse.pm
Revision 1.153.6.7: download - view: text, annotated - select for diffs
Wed Jan 25 12:00:33 2012 UTC (12 years, 3 months ago) by foxr
Branches: BZ4492-feature_horizontal_radioresponse
Diff to branchpoint 1.153: preferred, unified
Clean up errors in survey rendeing..still need to support horiztonal rendering
in survey mode which will be preceded by radical refactoring of displayallfoils.

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>