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