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