Annotation of loncom/homework/lonproblem.pm, revision 1.2

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>