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