Annotation of loncom/homework/lonproblem.pm, revision 1.4
1.4 ! harris41 1: # The LON-CAPA problem handler
! 2: #
1.1 albertel 3: # Problem Handler
4: #
1.2 harris41 5: # 12/15-01/21,01/24 Gerd Kortemeyer
1.4 ! harris41 6: # 4/12 Guy Albertelli
! 7: # 8/6 Scott Harrison
1.1 albertel 8:
9: package Apache::lonproblem;
10:
11: use strict;
12: use HTML::TokeParser;
13: use Safe;
14: use Apache::File;
15:
16: # ================================================================ Main Handler
17: sub handler {
1.4 ! harris41 18: my $r=shift;
! 19: my @parsecontents;
! 20: my $parsestring;
! 21: my $outstring;
! 22:
! 23: {
! 24: my $fh=Apache::File->new($r->filename);
! 25: @parsecontents=<$fh>;
! 26: }
! 27:
! 28: $parsestring=join('',@parsecontents);
! 29:
! 30: print "<form>";
! 31:
! 32: &xmlparse($r,$parsestring,'web');
! 33:
! 34: print "\n---------------\n";
! 35: print "<form>";
! 36: &xmlparse($r,$parsestring,'edit');
! 37: $outstring=xmlparse($parsestring,'modified');
! 38: print "\n---------------\n$outstring\n";
! 39: return 1; #change to ok
1.1 albertel 40: }
41:
42: # ============================================================= Parsing Routine
43: # Takes $parsestring and $target
44: sub xmlparse {
1.3 albertel 45:
1.4 ! harris41 46: my ($r,$parsestring,$target) = @_;
1.3 albertel 47:
1.4 ! harris41 48: my $safeeval = new Safe 'Script';
1.3 albertel 49:
1.4 ! harris41 50: my $parsereval = new Safe 'Parser';
! 51:
! 52: my $parser=HTML::TokeParser->new(\$parsestring);
1.3 albertel 53:
1.4 ! harris41 54: my $outtext='';
1.3 albertel 55:
1.1 albertel 56: # ---------------------------------------------------------------- Handled tags
57:
1.4 ! harris41 58: my %toptoplevel = ( 'problem' => 'Problem',
! 59: 'entryform' => 'Entry Form',
! 60: 'survey' => 'Survey',
! 61: 'graded' => 'Manually Graded' );
1.3 albertel 62:
63:
1.2 harris41 64: # --------------------------------------------------------------- Toplevel Tags
1.1 albertel 65:
1.4 ! harris41 66: my %topleveltags = ( 'block' => 'Condition Block',
! 67: 'part' => 'Problem Part',
! 68: 'include' => 'Include Section',
! 69: 'answer' => 'Answerfield',
! 70: 'script' => 'Script',
! 71: 'outtext' => 'Text Block' );
1.2 harris41 72:
73: # ---------------------------------------------------------- Preregistered Tags
1.1 albertel 74:
1.4 ! harris41 75: my %includetags = ( 'scriptlib' => 'Script Library',
! 76: 'parserlib' => 'Parser Library' );
1.3 albertel 77: # -------------------------------------------------------------Answer type Tags
78:
1.4 ! harris41 79: my %answertags = ( 'capaanswer' => 'CAPA Standard Answers');
1.2 harris41 80:
81: # -------------------------------------------------------------------- All Tags
82:
1.1 albertel 83:
1.4 ! harris41 84: my %xmltags = ( %includetags, %topleveltags, %toptoplevel,
! 85: %answertags );
1.3 albertel 86:
1.4 ! harris41 87: my $toplevel = '';
! 88: my $above = '';
1.3 albertel 89:
1.1 albertel 90: # --------------------------------------------------- Depth counter for editing
91:
1.4 ! harris41 92: my @depthcounter = ();
! 93: my $depth = -1;
! 94: my $olddepth = -1;
1.1 albertel 95:
96: # ----------------------------------------------------------------------- Stack
97:
1.4 ! harris41 98: my @stack = ('');
1.1 albertel 99:
100: # -------------------------------------------------------------- Init $saveeval
1.4 ! harris41 101:
! 102: &init_safeeval($safeeval);
1.1 albertel 103:
104: # ---------------------------------------------------------- Parse $parsestring
105:
1.4 ! harris41 106: my $token;
1.1 albertel 107:
1.4 ! harris41 108: while ($token = $parser->get_token) {
1.2 harris41 109: # =============================================================================
1.4 ! harris41 110: if ($token->[0] eq 'S') {
1.2 harris41 111: # =================================================================== Start Tag
112: # --------------------------------------------------------------- Depth Counter
1.4 ! harris41 113: if (defined($xmltags{$token->[1]})) {
! 114: if ($depth<$olddepth-1) {
! 115: $#depthcounter--;
! 116: $olddepth=$depth;
! 117: }
! 118: $depth++;
! 119: $depthcounter[$depth]++;
! 120: if ($depthcounter[$depth] == 1) {
! 121: $olddepth = $depth;
! 122: }
! 123: }
1.2 harris41 124: # -----------------------------------------------------------------------------
125:
126:
1.4 ! harris41 127: if ($target eq 'web') {
! 128: my $sub = "start_$token->[1]";
! 129: {
! 130: no strict 'refs';
! 131: if (defined (&$sub)) {
! 132: &$sub($r,$token,$parser,$safeeval,\@stack);
! 133: } else {
! 134: $stack[$#stack] .= $token->[4];
! 135: }
! 136: }
! 137: }
1.3 albertel 138:
1.4 ! harris41 139: if ($target eq 'edit') {
! 140: my $depthlabel = join('_',@depthcounter);
! 141: if (defined($xmltags{$token->[1]})) {
! 142: if (defined($topleveltags{$token->[1]})) {
! 143: &insertmenu($r,$xmltags{$token->[1]},
! 144: $depthlabel,\%topleveltags);
! 145: $toplevel = $token->[1];
! 146: } else {
! 147: if ($toplevel eq 'answer') {
! 148: &insertmenu($r,$xmltags{$token->[1]},
! 149: $depthlabel,\%answertags);
! 150: }
! 151: }
! 152: my $sub = "start_edit_$token->[1]";
! 153: {
! 154: no strict 'refs';
! 155: if (defined (&$sub)) {
! 156: &$sub($r,$token,$parser,$xmltags{$token->[1]},
! 157: $depthlabel,$above,\%answertypes,\@stack);
! 158: }
! 159: }
! 160: } else {
! 161: $stack[$#stack] .= $token->[4];
! 162: }
1.3 albertel 163: }
1.4 ! harris41 164:
! 165: if ($target eq 'modified') {
1.3 albertel 166: }
1.4 ! harris41 167:
1.2 harris41 168: # =============================================================================
1.4 ! harris41 169: } elsif ($token->[0] eq 'E') {
1.2 harris41 170: # ===================================================================== End Tag
171:
1.4 ! harris41 172: if ($target eq 'web') {
! 173: my $sub = "end_$token->[1]";
! 174: {
! 175: no strict 'refs';
! 176: if (defined (&$sub)) {
! 177: &$sub($r,$token,$parser,$safeeval,\@stack);
! 178: } else {
! 179: $stack[$#stack] .= $token->[2];
! 180: }
! 181: }
! 182: }
! 183:
! 184: if ($target eq 'edit') {
! 185: if (defined($xmltags{$token->[1]})) {
! 186: my $sub = "end_edit_$token->[1]";
! 187: {
! 188: no strict 'refs';
! 189: if (defined (&$sub)) {
! 190: &$sub($r,$token,$above,\@stack);
! 191: }
! 192: }
! 193: }
! 194: }
! 195:
! 196: if ($target eq 'modified') {
1.3 albertel 197: }
1.2 harris41 198: # --------------------------------------------------------------- Depth Counter
1.4 ! harris41 199: if (defined($xmltags{$token->[1]})) { $depth--; }
1.2 harris41 200: # -----------------------------------------------------------------------------
201: # =============================================================================
1.4 ! harris41 202: } elsif ($token->[0] eq 'T') {
1.2 harris41 203: # ================================================================= Parsed Text
1.4 ! harris41 204: $stack[$#stack] .= $token->[1];
! 205: }
1.3 albertel 206: }
1.4 ! harris41 207:
! 208: return $outtext;
1.1 albertel 209: }
210: # =============================================================================
211:
1.2 harris41 212: # --------------------------------------------------------------- Execute Token
1.1 albertel 213:
214:
215:
216: # ------------------------------------------------- Helper Routines for Editing
217:
218: sub rawprint {
1.4 ! harris41 219: my ($r,$data) = @_;
1.3 albertel 220: $r->print($data);
1.1 albertel 221: }
222:
223: sub insertmenu {
1.4 ! harris41 224: my ($r,$description,$depthlabel,$xmltagsref) = @_;
! 225: &rawprint($r,'<br><table bgcolor="#DDDD33" width="100%"><tr><td>');
! 226: &rawprint($r,"\n".'<select name="mod_menu_'.$depthlabel.'">'."\n");
! 227: &rawprint($r,'<option value="no_changes" selected>(no changes)</option>');
1.3 albertel 228: &rawprint($r,"\n".
1.4 ! harris41 229: '<option value="delete">Delete '.$description.
! 230: ' Below</option>');
! 231: my $key;
! 232: foreach $key (keys %$xmltagsref) {
! 233: &rawprint($r,"\n".
! 234: '<option value="insert_'.$key.'">Insert '.
! 235: $$xmltagsref{$key}.'</option>');
! 236: }
! 237: &rawprint($r,"\n".'</select></td></tr></table><br>'."\n");
1.1 albertel 238: }
1.2 harris41 239:
240: # =============================================================================
241: # ================================================ Routines for Safe Evaluation
242: # =============================================================================
243:
244: # -------------------------------------------- Initialize routines in $safeeval
245:
246: sub init_safeeval {
1.4 ! harris41 247: my $safeeval = shift;
! 248: my $initprg =<<'ENDINIT';
1.2 harris41 249:
250: # -------------------------------------------- Initializations inside $safeeval
251:
1.4 ! harris41 252: $e = 25;
! 253: $c = 20;
1.2 harris41 254:
1.3 albertel 255: ENDINIT
1.2 harris41 256: # ---------------------------------------------------------------- Execute that
1.3 albertel 257: $safeeval->reval($initprg);
1.2 harris41 258: }
259:
260: # ----------------------------------------------- Routines that use Safe Spaces
1.1 albertel 261:
262: sub printout {
1.4 ! harris41 263: my ($r,$data,$safespace) = @_;
! 264: $r->print($safespace->reval('return qq('.$data.');'));
1.1 albertel 265: }
266:
267: sub runfile {
1.4 ! harris41 268: my ($r,$filename,$safespace) = @_;
! 269: my $includefile;
! 270: if ($filename =~ /^\//) {
! 271: $includefile = $filename;
! 272: } else {
! 273: $includefile = $r->dir_config('lonIncludes');
! 274: $includefile .= '/'.$filename;
! 275: }
! 276: if (-e $includefile) {
! 277: $safespace->rdo($includefile);
! 278: }
1.1 albertel 279: }
280:
281: sub run {
1.4 ! harris41 282: my ($expression,$safespace) = @_;
! 283: $safespace->reval($expression);
1.1 albertel 284: }
285:
286: sub booleanexpr {
1.4 ! harris41 287: my ($expression,$safespace) = @_;
! 288: return $safespace->reval('return '.$expression.';');
1.1 albertel 289: }
290:
1.2 harris41 291:
292: # =============================================================================
293: # ================================================== Tag Handlers for Rendering
294: # =============================================================================
1.1 albertel 295:
296: sub start_block {
1.4 ! harris41 297: my ($r,$token,$parser,$safeeval,$stackref) = @_;
! 298: if (!booleanexpr($token->[2]{'condition'},$safeeval)) {
! 299: my $blockdepth = 0;
! 300: my $nexttoken;
! 301: while ($nexttoken=$parser->get_tag()) {
! 302: if ($nexttoken->[0] eq 'block') { $blockdepth++ };
! 303: if ($nexttoken->[0] eq '/block') {
! 304: if ($blockdepth == 0) {
! 305: return;
! 306: } else {
! 307: $blockdepth--;
! 308: }
! 309: }
1.3 albertel 310: }
311: }
1.4 ! harris41 312: return;
1.1 albertel 313: }
314:
315: sub start_script {
1.4 ! harris41 316: my ($r,$token,$parser,$safeeval,$stackref) = @_;
! 317: $stackref->[$#$stackref+1] = '';
1.1 albertel 318: }
319:
320: sub end_script {
1.4 ! harris41 321: my ($r,$token,$parser,$safeeval,$stackref) = @_;
! 322: &run($stackref->[$#$stackref],$safeeval);
! 323: $#$stackref--;
1.1 albertel 324: }
325:
326: sub start_outtext {
1.4 ! harris41 327: my ($r,$token,$parser,$safeeval,$stackref) = @_;
! 328: $stackref->[$#$stackref+1] = '';
1.1 albertel 329: }
330:
331: sub end_outtext {
1.4 ! harris41 332: my ($r,$token,$parser,$safeeval,$stackref) = @_;
! 333: &printout($r,$stackref->[$#$stackref],$safeeval);
! 334: $#$stackref--;
1.1 albertel 335: }
336:
337: sub start_inlinetext {
1.4 ! harris41 338: &start_outtext(@_);
1.1 albertel 339: }
340:
341: sub end_inlinetext {
1.4 ! harris41 342: &end_outtext(@_);
1.1 albertel 343: }
344:
1.2 harris41 345: sub start_scriptlib {
1.4 ! harris41 346: my ($r,$token,$parser,$safeeval,$stackref) = @_;
! 347: &runfile($r,$parser->get_text('/scriptlib'),$safeeval);
1.2 harris41 348: }
349:
350: sub start_parserlib {
1.4 ! harris41 351: my ($r,$token,$parser,$safeeval,$stackref) = @_;
! 352: &runfile($r,$parser->get_text('/parserlib'),$parsereval);
1.1 albertel 353: }
354:
1.2 harris41 355:
1.1 albertel 356: sub start_answer {
1.4 ! harris41 357: my ($r,$token,$parser,$safeeval,$stackref) = @_;
! 358: $stackref->[$#$stackref+1] = '<answer>::'.
! 359: join(':',map{$_.':'.$token->[2]->{$_}} @{$token->[3]});
! 360: $stackref->[$#$stackref+1] = '';
1.1 albertel 361: }
362:
363: sub end_answer {
1.4 ! harris41 364: my ($r,$token,$parser,$safeeval,$stackref) = @_;
! 365: my @itemtexts;
! 366: my @itemargs;
! 367: my $stackpointer = $#$stackref;
! 368: while (($stackref->[$stackpointer] !~ '<answer>::') &&
! 369: ($stackpointer > 0)) {
! 370: $stackpointer--;
! 371: }
! 372: my %answerargs=split(/:/,$stackref->[$stackpointer]);
1.1 albertel 373: }
374:
375: sub start_item {
1.4 ! harris41 376: my ($r,$token,$parser,$safeeval,$stackref) = @_;
! 377: $stackref->[$#$stackref+1] = '<item>::'.
! 378: join(':',map{$_.':'.$token->[2]->{$_}} @{$token->[3]});
! 379: $stackref->[$#$stackref+1]='';
1.1 albertel 380: }
381:
382: sub end_item {}
383:
1.2 harris41 384: # =============================================================================
385: # ==================================================== Tag Handlers for Editing
386: # =============================================================================
1.1 albertel 387:
388: sub start_edit_outtext {
1.4 ! harris41 389: my ($r,$token,$parser,$description,$depthlabel,$above,$answertyperef,
! 390: $stackref) = @_;
! 391: &rawprint($r,"\n<h3>$description</h3>".
! 392: '<textarea rows="10" cols="80" name="data_'.$depthlabel.'">');
! 393: $stackref->[$#$stackref+1] = '';
1.1 albertel 394: }
395:
396: sub end_edit_outtext {
1.4 ! harris41 397: my ($r,$token,$above,$stackref) = @_;
! 398: &rawprint($r,$stackref->[$#$stackref]."</textarea>\n");
! 399: $#$stackref--;
1.1 albertel 400: }
401:
402: sub start_edit_script {
1.4 ! harris41 403: &start_edit_outtext(@_);
1.1 albertel 404: }
405:
406: sub end_edit_script {
1.4 ! harris41 407: &end_edit_outtext(@_);
1.1 albertel 408: }
409:
410: sub start_edit_inlinetext {
1.4 ! harris41 411: &start_edit_outtext(@_);
1.1 albertel 412: }
413:
414: sub end_edit_inlinetext {
1.4 ! harris41 415: &end_edit_inlinetext(@_);
1.1 albertel 416: }
417:
418: sub start_edit_block {
1.4 ! harris41 419: my ($r,$token,$parser,$description,$depthlabel,$above,$answertyperef,
! 420: $stackref) = @_;
! 421: my $bgcolor = $depthlabel;
! 422: $bgcolor =~ s/\_//g;
! 423: $bgcolor = substr(length($bgcolor),-1,1);
! 424: $bgcolor =~ tr/1-5/A-E/;
! 425: $bgcolor = $bgcolor.'FFF'.$bgcolor.'A';
! 426: &rawprint($r,"\n".'<br><table border="2" cellpadding="10" bgcolor="#'.
! 427: $bgcolor.
! 428: '" width="100%"><tr><td><h3>'.$description.'</h3>');
1.1 albertel 429: }
430:
431: sub end_edit_block {
1.4 ! harris41 432: my ($r,$token,$above,$stackref) = @_;
! 433: &rawprint($r,"\n".'</td></tr></table><br>');
1.1 albertel 434: }
435:
436: sub start_edit_answer {
1.4 ! harris41 437: my ($r,$token,$parser,$description,$depthlabel,$above,$answertyperef,
! 438: $stackref) = @_;
! 439: start_edit_block(@_);
! 440: $above = $token->[2]{'type'};
! 441: &rawprint($r,"\n".'<select name="mod_type_'.$depthlabel.'">');
! 442: my $key;
! 443: foreach $key (keys %$answertyperef) {
! 444: &rawprint($r,"\n".'<option value="'.$key.'"');
! 445: if ($above eq $key) { &rawprint($r,' selected'); }
! 446: &rawprint($r,'>'.$$answertyperef{$key}.'</option>');
! 447: }
! 448: &rawprint($r,"\n".'</select>'."\n");
1.1 albertel 449: }
450:
451: sub end_edit_answer {
1.4 ! harris41 452: my ($r,$token,$above,$stackref)=@_;
! 453: end_edit_block(@_);
1.1 albertel 454: }
455:
456: sub start_edit_include {
1.4 ! harris41 457: start_edit_block(@_);
1.1 albertel 458: }
459:
460: sub end_edit_include {
1.4 ! harris41 461: end_edit_block(@_);
1.1 albertel 462: }
463:
464: sub start_edit_problem {
1.4 ! harris41 465: start_edit_block(@_);
1.1 albertel 466: }
467:
468: sub end_edit_problem {
1.4 ! harris41 469: end_edit_block(@_);
1.1 albertel 470: }
471:
472: 1;
1.4 ! harris41 473:
1.1 albertel 474: __END__
1.3 albertel 475:
1.1 albertel 476:
477:
478:
479:
480:
481:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>