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