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