File:  [LON-CAPA] / loncom / homework / radiobuttonresponse.pm
Revision 1.153.6.4: download - view: text, annotated - select for diffs
Mon Jan 23 12:00:13 2012 UTC (12 years, 3 months ago) by foxr
Branches: BZ4492-feature_horizontal_radioresponse
Diff to branchpoint 1.153: preferred, unified
BZ 4492 More refactoring prior to implementing latex direction rendering
        selection.

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

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