Annotation of loncom/homework/hint.pm, revision 1.52
1.21 albertel 1: # The LearningOnline Network with CAPA
2: # implements the tags that control the hints
3: #
1.52 ! albertel 4: # $Id: hint.pm,v 1.51 2004/03/16 19:47:47 albertel Exp $
1.21 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: #
1.33 albertel 10: # LON-CAPA me&aree software; you can redistribute it and/or modify
1.21 albertel 11: # it under the terms of the GNU General Public License as published by
12: # the Free Software Foundation; either version 2 of the License, or
13: # (at your option) any later version.
14: #
15: # LON-CAPA is distributed in the hope that it will be useful,
16: # but WITHOUT ANY WARRANTY; without even the implied warranty of
17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18: # GNU General Public License for more details.
19: #
20: # You should have received a copy of the GNU General Public License
21: # along with LON-CAPA; if not, write to the Free Software
22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23: #
24: # /home/httpd/html/adm/gpl.txt
25: #
26: # http://www.lon-capa.org/
27: #
28:
1.1 albertel 29: package Apache::hinttags;
30:
31: use strict;
32: use Apache::lonnet;
1.6 albertel 33: use capa;
1.1 albertel 34:
1.25 harris41 35: BEGIN {
1.39 albertel 36: &Apache::lonxml::register('Apache::hinttags',('hintgroup','hintpart','numericalhint','stringhint','formulahint','optionhint','radiobuttonhint'));
1.1 albertel 37: }
38:
1.2 albertel 39:
1.15 albertel 40: @Apache::hint::which=();
1.1 albertel 41: sub start_hintgroup {
1.39 albertel 42: my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
43: my $skiptoend='0';
44: my $result;
45:
46: if ($target eq 'web') {
47: my $id=$Apache::inputtags::part;
48: my $numtries=$Apache::lonhomework::history{"resource.$id.tries"};
49: if ( $numtries eq '') { $numtries = 0; }
1.52 ! albertel 50: my $hinttries=&Apache::response::get_response_param($id,"hinttries",1);
1.39 albertel 51: &Apache::lonxml::debug("found :$id:$numtries:$hinttries:");
1.46 albertel 52: my $gradestatus=$Apache::lonhomework::history{"resource.$id.solved"};
53: if ( $numtries < $hinttries || $gradestatus =~ /^correct/) {
1.39 albertel 54: &Apache::lonxml::get_all_text("/hintgroup",$parser);
55: }
1.40 albertel 56: &Apache::lonxml::startredirection;
1.39 albertel 57: } elsif ($target eq 'tex') {
58: $result .= '\keephidden{';
1.20 albertel 59: }
1.39 albertel 60: @Apache::hint::which=();
61: return $result;
1.1 albertel 62: }
63:
64: sub end_hintgroup {
1.39 albertel 65: my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
66: my $result;
1.20 albertel 67:
1.39 albertel 68: if ($target eq 'web') {
69: my $id=$Apache::inputtags::part;
70: my $numtries=$Apache::lonhomework::history{"resource.$id.tries"};
71: if ( $numtries eq '') { $numtries = 0; }
1.52 ! albertel 72: my $hinttries=&Apache::response::get_response_param($id,"hinttries",1);
1.39 albertel 73: &Apache::lonxml::debug("found :$id:$numtries:$hinttries:");
1.40 albertel 74: my $hinttext=&Apache::lonxml::endredirection;
75: if ($Apache::lonhomework::type ne 'exam' &&
1.41 albertel 76: $numtries >= $hinttries && $hinttext =~/\S/) {
1.40 albertel 77: $result='<table bgcolor="#dddddd"><tr><td>'.
78: $hinttext.'</td></tr></table>';
1.38 albertel 79: }
1.39 albertel 80: } elsif ($target eq 'edit') {
81: $result.=&Apache::edit::end_table();
82: } elsif ($target eq 'tex') {
83: $result .= '}';
1.19 albertel 84: }
1.39 albertel 85: @Apache::hint::which=();
86: return $result;
1.3 albertel 87: }
88:
89: sub start_numericalhint {
1.39 albertel 90: my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
91: #do everything in end, so intervening <responseparams> work
92: &Apache::response::start_hintresponse($parstack,$safeeval);
93: my $result;
94: if ($target eq 'edit') {
95: $result.=&Apache::edit::tag_start($target,$token);
96: $result.=&Apache::edit::text_arg('Name:','name',$token);
97: $result.=&Apache::edit::text_arg('Answer:','answer',$token);
98: if ($token->[1] eq 'numericalhint') {
99: $result.=&Apache::edit::text_arg('Unit:','unit',$token,5).
100: &Apache::loncommon::help_open_topic('Physical_Units');
101: $result.=&Apache::edit::text_arg('Format:','format',$token,4).
102: &Apache::loncommon::help_open_topic('Numerical_Response_Format');
103: } elsif ($token->[1] eq 'stringhint') {
1.44 albertel 104: $result.=&Apache::edit::select_arg('Type:','type',
105: [['cs','Case Sensitive'],['ci','Case Insensitive'],
106: ['mc','Case Insensitive, Any Order']],$token);
1.39 albertel 107: } elsif ($token->[1] eq 'formulahint') {
108: $result.=&Apache::edit::text_arg('Sample Points:','samples',$token,40);
109: }
110: $result.=&Apache::edit::end_row();
111: $result.=&Apache::edit::start_spanning_row();
112: } elsif ($target eq 'modified') {
113: my $constructtag;
114: if ($token->[1] eq 'numericalhint') {
115: $constructtag=&Apache::edit::get_new_args($token,$parstack,
116: $safeeval,'name',
117: 'answer','unit','format');
118: } elsif ($token->[1] eq 'stringhint') {
119: $constructtag=&Apache::edit::get_new_args($token,$parstack,
120: $safeeval,'name','answer',
121: 'type');
122: } elsif ($token->[1] eq 'formulahint') {
123: $constructtag=&Apache::edit::get_new_args($token,$parstack,
124: $safeeval,'name','answer',
125: 'samples');
126: }
127: if ($constructtag) {
128: $result = &Apache::edit::rebuild_tag($token);
129: $result .= &Apache::edit::handle_insert();
130: }
131: } elsif ($target eq 'web') {
132: &Apache::response::reset_params();
1.28 albertel 133: }
1.39 albertel 134: return $result;
1.3 albertel 135: }
136:
137: sub end_numericalhint {
1.39 albertel 138: my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
139: my $result;
140: if ($target eq 'web') {
141: if (!$Apache::lonxml::default_homework_loaded) {
142: &Apache::lonxml::default_homework_load($safeeval);
143: }
144: $safeeval->share_from('capa',['&caparesponse_capa_check_answer']);
145: my $name= &Apache::lonxml::get_param('name',$parstack,$safeeval);
1.48 albertel 146: &Apache::response::setup_params('numericalhint',$safeeval);
1.39 albertel 147: my $partid=$Apache::inputtags::part;
148: my $id=$Apache::inputtags::response['-1'];
149: #id submissions occured under
150: my $submitid=$Apache::inputtags::response['-2'];
151: my $response = $Apache::lonhomework::history{
1.18 albertel 152: "resource.$partid.$submitid.submission"};
1.39 albertel 153: &Apache::lonxml::debug("hintgroup is using $response<br />\n");
1.52 ! albertel 154: my $hideunit=&Apache::response::get_response_param($submitid.'_'.$id,
! 155: 'turnoffunit');
1.51 albertel 156: my $args_ref= \%{$safeeval->varglob('LONCAPA::CAPAresponse_args')};
157: $$args_ref{'response'}=$response;
1.39 albertel 158: #need to get all possible parms
1.51 albertel 159: foreach my $arg ('type','tol','sig','ans_fmt','unit','calc',
160: 'samples') {
161: $$args_ref{$arg}=
162: &Apache::lonxml::get_param($arg,$parstack,$safeeval);
163: }
1.39 albertel 164: foreach my $key (keys(%Apache::inputtags::params)) {
1.51 albertel 165: $$args_ref{$key}=$Apache::inputtags::params{$key};
1.43 albertel 166: }
1.51 albertel 167: if (lc($hideunit) eq "yes") { delete($$args_ref{'unit'}); }
1.43 albertel 168: if ($$tagstack[-1] eq 'formulahint') {
1.51 albertel 169: $$args_ref{'type'}='fml';
1.43 albertel 170: } elsif ($$tagstack[-1] eq 'numericalhint') {
1.51 albertel 171: $$args_ref{'type'}='float';
1.39 albertel 172: }
1.45 albertel 173: my @answer=&Apache::lonxml::get_param_var('answer',$parstack,$safeeval);
174: &Apache::lonxml::debug('answer is'.join(':',@answer));
1.51 albertel 175: @{$safeeval->varglob('LONCAPA::CAPAresponse_answer')}=@answer;
1.45 albertel 176:
1.51 albertel 177: ($result,my @msgs) = &Apache::run::run("&caparesponse_check_list()",
178: $safeeval);
1.50 albertel 179: &Apache::lonxml::debug('msgs are'.join(':',@msgs));
1.51 albertel 180: &Apache::lonxml::debug("result:$result:$Apache::lonxml::curdepth");
1.50 albertel 181: my ($awards)=split(/:/,$result);
182: my (@awards) = split(/,/,$awards);
183: my ($ad, $msg) = &Apache::inputtags::finalizeawards(\@awards,\@msgs);
1.39 albertel 184: if ($ad eq 'EXACT_ANS' || $ad eq 'APPROX_ANS') { push (@Apache::hint::which,$name); }
185: $result='';
186: } elsif ($target eq 'meta') {
187: $result=&Apache::response::meta_package_write($token->[1]);
188: } elsif ($target eq 'edit') {
189: $result.='</td></tr>'.&Apache::edit::end_table;
1.18 albertel 190: }
1.39 albertel 191: &Apache::response::end_hintresponse();
192: return $result;
1.28 albertel 193: }
194:
1.51 albertel 195: sub start_formulahint {
1.35 albertel 196: return &start_numericalhint(@_);
1.28 albertel 197: }
198:
1.51 albertel 199: sub end_formulahint {
1.35 albertel 200: return &end_numericalhint(@_);
1.28 albertel 201: }
202:
1.51 albertel 203: sub start_stringhint {
204: my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
205: #do everything in end, so intervening <responseparams> work
206: &Apache::response::start_hintresponse($parstack,$safeeval);
207: my $result;
208: if ($target eq 'edit') {
209: $result.=&Apache::edit::tag_start($target,$token);
210: $result.=&Apache::edit::text_arg('Name:','name',$token);
211: $result.=&Apache::edit::text_arg('Answer:','answer',$token);
212: $result.=&Apache::edit::select_arg('Type:','type',
213: [['cs','Case Sensitive'],['ci','Case Insensitive'],
214: ['mc','Case Insensitive, Any Order'],
215: ['re','Regular Expression']],$token);
216: $result.=&Apache::edit::end_row();
217: $result.=&Apache::edit::start_spanning_row();
218: } elsif ($target eq 'modified') {
219: my $constructtag;
220: $constructtag=&Apache::edit::get_new_args($token,$parstack,
221: $safeeval,'name','answer',
222: 'type');
223: $result = &Apache::edit::rebuild_tag($token);
224: $result .= &Apache::edit::handle_insert();
225: } elsif ($target eq 'web') {
226: &Apache::response::reset_params();
227: }
228: return $result;
1.28 albertel 229: }
230:
1.51 albertel 231: sub end_stringhint {
232: my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
233: my $result;
234: if ($target eq 'web') {
235: if (!$Apache::lonxml::default_homework_loaded) {
236: &Apache::lonxml::default_homework_load($safeeval);
237: }
238: my $answer=&Apache::lonxml::get_param('answer',$parstack,$safeeval);
239: $safeeval->share_from('capa',['&caparesponse_capa_check_answer']);
240: my $name= &Apache::lonxml::get_param('name',$parstack,$safeeval);
241: &Apache::response::setup_params('stringhint',$safeeval);
242: my $partid=$Apache::inputtags::part;
243: my $id=$Apache::inputtags::response['-1'];
244: #id submissions occured under
245: my $submitid=$Apache::inputtags::response['-2'];
246: my $response = $Apache::lonhomework::history{
247: "resource.$partid.$submitid.submission"};
248: &Apache::lonxml::debug("hintgroup is using $response<br />\n");
249: my $args_ref= \%{$safeeval->varglob('LONCAPA::CAPAresponse_args')};
250: $$args_ref{'response'}=$response;
251: my $type=$$args_ref{'type'}=&Apache::lonxml::get_param('type',$parstack,$safeeval);
252: my ($ad,$msg);
253: if ($type eq 're' ) {
254: ${$safeeval->varglob('LONCAPA::response')}=$response;
255: $result = &Apache::run::run('return $LONCAPA::response=~m'.$answer,$safeeval);
256: &Apache::lonxml::debug("current $response");
257: &Apache::lonxml::debug("current $answer");
258: $ad = ($result) ? 'APPROX_ANS' : 'INCORRECT';
259: } else {
260: foreach my $key (keys(%Apache::inputtags::params)) {
261: $$args_ref{$key}=$Apache::inputtags::params{$key};
262: }
263: &Apache::lonxml::debug('answer is'.$answer);
264: @{$safeeval->varglob('LONCAPA::CAPAresponse_answer')}=($answer);
265:
266: ($result,my @msgs)=&Apache::run::run("&caparesponse_check_list()",
267: $safeeval);
268: &Apache::lonxml::debug('msgs are'.join(':',@msgs));
269: &Apache::lonxml::debug("result:$result:$Apache::lonxml::curdepth");
270: my ($awards)=split(/:/,$result);
271: my (@awards) = split(/,/,$awards);
272: ($ad, $msg) = &Apache::inputtags::finalizeawards(\@awards,\@msgs);
273: }
274: if ($ad eq 'EXACT_ANS' || $ad eq 'APPROX_ANS') {
275: push (@Apache::hint::which,$name);
276: }
277: $result='';
278: } elsif ($target eq 'meta') {
279: $result=&Apache::response::meta_package_write($token->[1]);
280: } elsif ($target eq 'edit') {
281: $result.='</td></tr>'.&Apache::edit::end_table;
282: }
283: &Apache::response::end_hintresponse();
284: return $result;
1.1 albertel 285: }
286:
1.2 albertel 287: # a part shows if it is on, if no specific parts are on, then default shows
1.1 albertel 288: sub start_hintpart {
1.39 albertel 289: my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
1.15 albertel 290:
1.39 albertel 291: my $show ='0';
292: my $result = '';
293: if ($target eq 'web') {
294: my $on= &Apache::lonxml::get_param('on',$parstack,$safeeval);
295: &Apache::lonxml::debug("hintpart sees $on and ,$#Apache::hint::which");
296: if ( $on eq 'default' && $#Apache::hint::which == '-1') {
297: $show=1;
298: } else {
299: my $which;
300: foreach $which (@Apache::hint::which) { if ($which eq $on) { $show = 1; last } }
301: }
302: if (!$show) {
303: &Apache::lonxml::get_all_text("/hintpart",$parser);
304: }
305: } elsif ($target eq 'grade') {
306: &Apache::lonxml::get_all_text("/hintpart",$parser);
307: } elsif ($target eq 'edit') {
308: $result.= &Apache::edit::tag_start($target,$token);
309: $result.= &Apache::edit::text_arg('On:','on',$token);
310: $result.= &Apache::edit::end_row();
311: $result.= &Apache::edit::start_spanning_row();
312: } elsif ($target eq 'modified') {
313: my $constructtag=&Apache::edit::get_new_args($token,$parstack,
314: $safeeval,'on');
315: if ($constructtag) {
316: $result = &Apache::edit::rebuild_tag($token);
317: $result.=&Apache::edit::handle_insert();
318: }
1.20 albertel 319: }
1.39 albertel 320: return $result;
1.1 albertel 321: }
322:
323: sub end_hintpart {
1.29 albertel 324: my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
325: my $result;
326: if ($target eq 'edit') { $result.=&Apache::edit::end_table; }
327: return $result;
328: }
329:
330: sub start_optionhint {
331: my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
332: my $result;
1.30 albertel 333: &Apache::response::start_hintresponse($parstack,$safeeval);
334: if ($target eq 'edit') {
335: $result.=&Apache::edit::tag_start($target,$token);
336: $result.=&Apache::edit::text_arg('Name:','name',$token);
337: $result.=&Apache::edit::text_arg('Answer:','answer',$token,40);
338: $result.=&Apache::edit::text_arg('Concept:','concept',$token,50);
339: } elsif ($target eq 'modified') {
340: my $constructtag=&Apache::edit::get_new_args($token,$parstack,
341: $safeeval,'name',
342: 'answer','concept');
343: if ($constructtag) {
344: $result = &Apache::edit::rebuild_tag($token);
345: $result .= &Apache::edit::handle_insert();
346: }
347: } elsif ($target eq 'meta') {
348: $result=&Apache::response::meta_package_write('numericalhint');
349: }
1.29 albertel 350: return $result;
351: }
352:
353: sub end_optionhint {
354: my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
355: my $result;
1.30 albertel 356: if ($target eq 'web') {
357: my ($foilmatch,$conceptmatch)=(-1,-1);
358: my $name= &Apache::lonxml::get_param('name',$parstack,$safeeval);
359: my $partid=$Apache::inputtags::part;
360: #id submissions occured under
361: my $submitid=$Apache::inputtags::response['-2'];
362: my $part_id="$partid.$submitid";
363: my %answer;
364: my $answer=&Apache::lonxml::get_param('answer',$parstack,$safeeval);
365: if ($answer) {
366: eval('%answer ='.$answer);
367: &Apache::lonhomework::showhash(%answer);
368: my $response = $Apache::lonhomework::history{
369: "resource.$part_id.submission"};
370: my %response=&Apache::lonnet::str2hash($response);
371: &Apache::lonhomework::showhash(%response);
372: foreach my $foil (keys(%answer)) {
373: $foilmatch=1;
374: if ($answer{$foil} ne $response{$foil}) {$foilmatch=0;last;}
375: }
376: }
377: my %concept;
378: my $constr=&Apache::lonxml::get_param('concept',$parstack,$safeeval);
379: if ( $constr ) { eval('%concept ='.$constr); }
380: my $response = $Apache::lonhomework::history{
381: "resource.$part_id.submissiongrading"};
382: my %response=&Apache::lonnet::str2hash($response);
383: foreach my $concept (keys(%concept)) {
384: my $compare;
385: if ($concept{$concept} eq 'correct') {$compare=1}else{$compare=0}
386: $conceptmatch=1;
387: if (ref($Apache::hint::option{"$part_id.concepts"})) {
388: foreach my $foil (@{ $Apache::hint::option{"$part_id.concept.$concept"} }) {
389: &Apache::lonxml::debug("compare -$foil- -$response{$foil}-$compare-");
390: if ( exists($response{$foil}) &&
391: $response{$foil} ne $compare) {$conceptmatch=0;last;}
392: }
393: } else {
394: $conceptmatch=0;
395: }
396: if ($conceptmatch eq '0') { last; }
397: }
398: if ( ($conceptmatch eq '-1' || $conceptmatch eq '1') &&
399: ($foilmatch eq '-1' || $foilmatch eq '1') ) {
400: push(@Apache::hint::which,$name);
401: }
402: } elsif ($target eq 'edit') { $result.=&Apache::edit::end_table; }
1.29 albertel 403: if ($target eq 'edit') { $result.=&Apache::edit::end_table; }
1.30 albertel 404: &Apache::response::end_hintresponse();
1.29 albertel 405: return $result;
406: }
407:
408: sub start_radiobuttonhint {
409: my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
410: my $result;
411: &Apache::response::start_hintresponse($parstack,$safeeval);
412: if ($target eq 'edit') {
413: $result.=&Apache::edit::tag_start($target,$token);
414: $result.=&Apache::edit::text_arg('Name:','name',$token);
415: $result.=&Apache::edit::text_arg('Answer:','answer',$token);
416: } elsif ($target eq 'modified') {
417: my $constructtag=&Apache::edit::get_new_args($token,$parstack,
418: $safeeval,'name',
419: 'answer');
420: if ($constructtag) {
421: $result = &Apache::edit::rebuild_tag($token);
422: $result .= &Apache::edit::handle_insert();
423: }
424: } elsif ($target eq 'meta') {
425: $result=&Apache::response::meta_package_write('numericalhint');
426: }
427: return $result;
1.1 albertel 428: }
429:
1.31 albertel 430: sub end_radiobuttonhint {
1.29 albertel 431: my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
432: my $result;
433: if ($target eq 'web') {
434: my $name= &Apache::lonxml::get_param('name',$parstack,$safeeval);
435: my @answer;
436: my $answer=&Apache::lonxml::get_param('answer',$parstack,$safeeval);
437: eval('@answer ='.$answer);
438: my $partid=$Apache::inputtags::part;
439: #id submissions occured under
440: my $submitid=$Apache::inputtags::response['-2'];
441: my $part_id="$partid.$submitid";
442: my $response = $Apache::lonhomework::history{
443: "resource.$part_id.submission"};
444: ($response)=&Apache::lonnet::str2hash($response);
1.42 albertel 445: &Apache::lonxml::debug("response is $response");
446:
447: if ($answer[0] eq 'foil') {
448: shift(@answer);
449: foreach my $answer (@answer) {
450: if ($response eq $answer) {
451: push (@Apache::hint::which,$name);
452: last;
453: }
454: }
1.29 albertel 455: } elsif ($answer[0] eq 'concept') {
1.42 albertel 456: shift(@answer);
457: foreach my $answer (@answer) {
458: if (ref($Apache::hint::radiobutton{"$part_id.concept.".$answer})) {
459: my @names=@{ $Apache::hint::radiobutton{"$part_id.concept.".$answer} };
460: if (grep(/^\Q$response\E$/,@names)) {
461: push(@Apache::hint::which,$name);
462: last;
463: }
1.29 albertel 464: }
465: }
466: }
467: } elsif ($target eq 'edit') { $result.=&Apache::edit::end_table; }
468: &Apache::response::end_hintresponse();
469: return $result;
470: }
1.1 albertel 471: 1;
472: __END__
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>