File:
[LON-CAPA] /
loncom /
xml /
lonxml.pm
Revision
1.132:
download - view:
text,
annotated -
select for diffs
Mon Oct 1 20:06:45 2001 UTC (22 years, 9 months ago) by
albertel
Branches:
MAIN
CVS tags:
HEAD
- added get_param_var (Will also evaluate paramater values that look like variable references inside the safe spacebefore returning them, should successfully handle both arrays, and hashes.) (Should the extra code be integrated back into get_param?)
1: # The LearningOnline Network with CAPA
2: # XML Parser Module
3: #
4: # last modified 06/26/00 by Alexander Sakharuk
5: # 11/6 Gerd Kortemeyer
6: # 6/1/1 Gerd Kortemeyer
7: # 2/21,3/13 Guy
8: # 3/29,5/4 Gerd Kortemeyer
9: # 5/10 Scott Harrison
10: # 5/26 Gerd Kortemeyer
11: # 5/27 H. K. Ng
12: # 6/2,6/3,6/8,6/9 Gerd Kortemeyer
13: # 6/12,6/13 H. K. Ng
14: # 6/16 Gerd Kortemeyer
15: # 7/27 H. K. Ng
16: # 8/7,8/9,8/10,8/11,8/15,8/16,8/17,8/18,8/20,8/23,8/24 Gerd Kortemeyer
17: # Guy Albertelli
18: # 9/26 Gerd Kortemeyer
19:
20:
21: package Apache::lonxml;
22: use vars
23: qw(@pwd @outputstack $redirection $import @extlinks $metamode $evaluate %insertlist @namespace);
24: use strict;
25: use HTML::TokeParser;
26: use HTML::TreeBuilder;
27: use Safe;
28: use Safe::Hole;
29: use Math::Cephes qw(:trigs :hypers :bessels erf erfc);
30: use Math::Random qw(:all);
31: use Opcode;
32:
33: sub register {
34: my $space;
35: my @taglist;
36: my $temptag;
37: ($space,@taglist) = @_;
38: foreach $temptag (@taglist) {
39: $Apache::lonxml::alltags{$temptag}=$space;
40: }
41: }
42:
43: use Apache::Constants qw(:common);
44: use Apache::lontexconvert;
45: use Apache::style;
46: use Apache::run;
47: use Apache::londefdef;
48: use Apache::scripttag;
49: use Apache::edit;
50: use Apache::lonnet;
51: use Apache::File;
52:
53: #================================================== Main subroutine: xmlparse
54: #debugging control, to turn on debugging modify the correct handler
55: $Apache::lonxml::debug=0;
56:
57: #path to the directory containing the file currently being processed
58: @pwd=();
59:
60: #these two are used for capturing a subset of the output for later processing,
61: #don't touch them directly use &startredirection and &endredirection
62: @outputstack = ();
63: $redirection = 0;
64:
65: #controls wheter the <import> tag actually does
66: $import = 1;
67: @extlinks=();
68:
69: # meta mode is a bit weird only some output is to be turned off
70: #<output> tag turns metamode off (defined in londefdef.pm)
71: $metamode = 0;
72:
73: # turns on and of run::evaluate actually derefencing var refs
74: $evaluate = 1;
75:
76: # data structure for eidt mode, determines what tags can go into what other tags
77: %insertlist=();
78:
79: # stores the list of active tag namespaces
80: @namespace=();
81:
82: # has the dynamic menu been updated to know about this resource
83: $Apache::lonxml::registered=0;
84:
85: sub xmlbegin {
86: my $output='';
87: if ($ENV{'browser.mathml'}) {
88: $output='<?xml version="1.0"?>'
89: .'<?xml-stylesheet type="text/css" href="/adm/MathML/mathml.css"?>'
90: .'<!DOCTYPE html SYSTEM "/adm/MathML/mathml.dtd" '
91: .'[<!ENTITY mathns "http://www.w3.org/1998/Math/MathML">]>'
92: .'<html xmlns:math="http://www.w3.org/1998/Math/MathML" '
93: .'xmlns="http://www.w3.org/TR/REC-html40">';
94: } else {
95: $output='<html>';
96: }
97: return $output;
98: }
99:
100: sub xmlend {
101: my $discussion='';
102: if ($ENV{'request.course.id'}) {
103: my $crs='/'.$ENV{'request.course.id'};
104: if ($ENV{'request.course.sec'}) {
105: $crs.='_'.$ENV{'request.course.sec'};
106: }
107: $crs=~s/\_/\//g;
108: my $seeid=&Apache::lonnet::allowed('rin',$crs);
109: my $symb=&Apache::lonnet::symbread();
110: if ($symb) {
111: my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},
112: $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
113: $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
114: if ($contrib{'version'}) {
115: $discussion.=
116: '<address><hr /><h2>Course Discussion of Resource</h2>';
117: my $idx;
118: for ($idx=1;$idx<=$contrib{'version'};$idx++) {
119: my $hidden=($contrib{'hidden'}=~/\.$idx\./);
120: unless (($hidden) && (!$seeid)) {
121: my $message=$contrib{$idx.':message'};
122: $message=~s/\n/\<br \/\>/g;
123: if ($message) {
124: if ($hidden) {
125: $message='<font color="#888888">'.$message.'</font>';
126: }
127: my $sender='Anonymous';
128: if ((!$contrib{$idx.':anonymous'}) || ($seeid)) {
129: $sender=$contrib{$idx.':sendername'}.' at '.
130: $contrib{$idx.':senderdomain'};
131: if ($contrib{$idx.':anonymous'}) {
132: $sender.=' (anonymous)';
133: }
134: if ($seeid) {
135: if ($hidden) {
136: $sender.=' <a href="/adm/feedback?unhide='.
137: $symb.':::'.$idx.'">Make Visible</a>';
138: } else {
139: $sender.=' <a href="/adm/feedback?hide='.
140: $symb.':::'.$idx.'">Hide</a>';
141: }
142: }
143: }
144: $discussion.='<p><b>'.$sender.'</b> ('.
145: localtime($contrib{$idx.':timestamp'}).
146: '):<blockquote>'.$message.
147: '</blockquote></p>';
148: }
149: }
150: }
151: $discussion.='</address>';
152: }
153: }
154: }
155: return $discussion.'</html>';
156: }
157:
158: sub tokeninputfield {
159: my $defhost=$Apache::lonnet::perlvar{'lonHostID'};
160: $defhost=~tr/a-z/A-Z/;
161: return (<<ENDINPUTFIELD)
162: <script>
163: function updatetoken() {
164: var comp=new Array;
165: var barcode=unescape(document.tokeninput.barcode.value);
166: comp=barcode.split('*');
167: if (typeof(comp[0])!="undefined") {
168: document.tokeninput.codeone.value=comp[0];
169: }
170: if (typeof(comp[1])!="undefined") {
171: document.tokeninput.codetwo.value=comp[1];
172: }
173: if (typeof(comp[2])!="undefined") {
174: comp[2]=comp[2].toUpperCase();
175: document.tokeninput.codethree.value=comp[2];
176: }
177: document.tokeninput.barcode.value='';
178: }
179: </script>
180: <form method="post" name="tokeninput">
181: <table border="2" bgcolor="#FFFFBB">
182: <tr><th>DocID Checkin</th></tr>
183: <tr><td>
184: <table>
185: <tr>
186: <td>Scan in Barcode</td>
187: <td><input type="text" size="22" name="barcode"
188: onChange="updatetoken()"/></td>
189: </tr>
190: <tr><td><i>or</i> Type in DocID</td>
191: <td>
192: <input type="text" size="5" name="codeone" />
193: <b><font size="+2">*</font></b>
194: <input type="text" size="5" name="codetwo" />
195: <b><font size="+2">*</font></b>
196: <input type="text" size="10" name="codethree" value="$defhost"
197: onChange="this.value=this.value.toUpperCase()" />
198: </td></tr>
199: </table>
200: </td></tr>
201: <tr><td><input type="submit" value="Check in DocID" /></td></tr>
202: </table>
203: </form>
204: ENDINPUTFIELD
205: }
206:
207: sub maketoken {
208: my ($symb,$tuname,$tudom,$tcrsid)=@_;
209: unless ($symb) {
210: $symb=&Apache::lonnet::symbread();
211: }
212: unless ($tuname) {
213: $tuname=$ENV{'user.name'};
214: $tudom=$ENV{'user.domain'};
215: $tcrsid=$ENV{'request.course.id'};
216: }
217:
218: return &Apache::lonnet::checkout($symb,$tuname,$tudom,$tcrsid);
219: }
220:
221: sub printtokenheader {
222: my ($target,$token,$symb,$tuname,$tudom,$tcrsid)=@_;
223: unless ($token) { return ''; }
224:
225: unless ($symb) {
226: $symb=&Apache::lonnet::symbread();
227: }
228: unless ($tuname) {
229: $tuname=$ENV{'user.name'};
230: $tudom=$ENV{'user.domain'};
231: $tcrsid=$ENV{'request.course.id'};
232: }
233:
234: my %reply=&Apache::lonnet::get('environment',
235: ['firstname','middlename','lastname','generation'],
236: $tudom,$tuname);
237: my $plainname=$reply{'firstname'}.' '.
238: $reply{'middlename'}.' '.
239: $reply{'lastname'}.' '.
240: $reply{'generation'};
241:
242: if ($target eq 'web') {
243: return
244: '<img align="right" src="/cgi-bin/barcode.gif?encode='.$token.'" />'.
245: 'Checked out for '.$plainname.
246: '<br />User: '.$tuname.' at '.$tudom.
247: '<br />CourseID: '.$tcrsid.
248: '<br />DocID: '.$token.
249: '<br />Time: '.localtime().'<hr />';
250: } else {
251: return $token;
252: }
253: }
254:
255: sub fontsettings() {
256: my $headerstring='';
257: if (($ENV{'browser.os'} eq 'mac') && (!$ENV{'browser.mathml'})) {
258: $headerstring.=
259: '<meta Content-Type="text/html; charset=x-mac-roman">';
260: }
261: return $headerstring;
262: }
263:
264: sub registerurl {
265: my $forcereg=shift;
266: if ($ENV{'request.publicaccess'}) {
267: return
268: '<script>function LONCAPAreg(){} function LONCAPAstale(){}</script>';
269: }
270: if ($Apache::lonxml::registered && !$forcereg) { return ''; }
271: $Apache::lonxml::registered=1;
272: if (($ENV{'REQUEST_URI'}!~/^\/(res\/)*adm\//) || ($forcereg)) {
273: my $hwkadd='';
274: if ($ENV{'REQUEST_URI'}=~/\.(problem|exam|quiz|assess|survey|form)$/) {
275: if (&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'})) {
276: $hwkadd.=(<<ENDSUBM);
277: menu.switchbutton
278: (7,1,'subm.gif','view sub','missions',
279: 'gocmd("/adm/grades","submission")');
280: ENDSUBM
281: }
282: if (&Apache::lonnet::allowed('mgr',$ENV{'request.course.id'})) {
283: $hwkadd.=(<<ENDGRDS);
284: menu.switchbutton
285: (7,2,'pgrd.gif','problem','grades',
286: 'gocmd("/adm/grades","viewgrades")');
287: ENDGRDS
288: }
289: if (&Apache::lonnet::allowed('opa',$ENV{'request.course.id'})) {
290: $hwkadd.=(<<ENDPARM);
291: menu.switchbutton
292: (7,3,'pparm.gif','problem','parms',
293: 'gocmd("/adm/parmset","set")');
294: ENDPARM
295: }
296: }
297: return (<<ENDREGTHIS);
298:
299: <script language="JavaScript">
300: // BEGIN LON-CAPA Internal
301:
302: function LONCAPAreg() {
303: menu=window.open("","LONCAPAmenu");
304: menu.clearTimeout(menu.menucltim);
305: menu.currentURL=window.location.pathname;
306: menu.currentStale=0;
307: menu.clearbut(3,1);
308: menu.switchbutton
309: (6,3,'catalog.gif','catalog','info','catalog_info()');
310: menu.switchbutton
311: (8,1,'eval.gif','evaluate','this','gopost("/adm/evaluate",currentURL)');
312: menu.switchbutton
313: (8,2,'fdbk.gif','feedback','on this','gopost("/adm/feedback",currentURL)');
314: menu.switchbutton
315: (8,3,'prt.gif','prepare','printout','gopost("/adm/printout",currentURL)');
316: menu.switchbutton
317: (2,1,'back.gif','backward','','gopost("/adm/flip","back:"+currentURL)');
318: menu.switchbutton
319: (2,3,'forw.gif','forward','','gopost("/adm/flip","forward:"+currentURL)');
320: menu.switchbutton
321: (9,1,'sbkm.gif','set','bookmark','set_bookmark()');
322: menu.switchbutton
323: (9,2,'vbkm.gif','view','bookmark','edit_bookmarks()');
324: menu.switchbutton
325: (9,3,'anot.gif','anno-','tations','annotate()');
326: $hwkadd
327: }
328:
329: function LONCAPAstale() {
330: menu=window.open("","LONCAPAmenu");
331: menu.currentStale=1;
332: menu.switchbutton
333: (3,1,'reload.gif','return','location','go(currentURL)');
334: menu.clearbut(7,1);
335: menu.clearbut(7,2);
336: menu.clearbut(7,3);
337: menu.menucltim=menu.setTimeout(
338: 'clearbut(2,1);clearbut(2,3);clearbut(8,1);clearbut(8,2);clearbut(8,3);'+
339: 'clearbut(9,1);clearbut(9,2);clearbut(9,3);clearbut(6,3)',
340: 2000);
341:
342: }
343:
344: // END LON-CAPA Internal
345: </script>
346: ENDREGTHIS
347:
348: } else {
349: return (<<ENDDONOTREGTHIS);
350:
351: <script language="JavaScript">
352: // BEGIN LON-CAPA Internal
353:
354: function LONCAPAreg() {
355: menu=window.open("","LONCAPAmenu");
356: menu.currentStale=1;
357: menu.clearbut(2,1);
358: menu.clearbut(2,3);
359: menu.clearbut(8,1);
360: menu.clearbut(8,2);
361: menu.clearbut(8,3);
362: if (menu.currentURL) {
363: menu.switchbutton
364: (3,1,'reload.gif','return','location','go(currentURL)');
365: } else {
366: menu.clearbut(3,1);
367: }
368: }
369:
370: function LONCAPAstale() {
371: }
372:
373: // END LON-CAPA Internal
374: </script>
375: ENDDONOTREGTHIS
376:
377: }
378: }
379:
380: sub loadevents() {
381: return 'LONCAPAreg();';
382: }
383:
384: sub unloadevents() {
385: return 'LONCAPAstale();';
386: }
387:
388: sub printalltags {
389: my $temp;
390: foreach $temp (sort keys %Apache::lonxml::alltags) {
391: &Apache::lonxml::debug("$temp -- $Apache::lonxml::alltags{$temp}");
392: }
393: }
394:
395: sub xmlparse {
396: my ($target,$content_file_string,$safeinit,%style_for_target) = @_;
397:
398: &setup_globals($target);
399: #&printalltags();
400: my @pars = ();
401: my $pwd=$ENV{'request.filename'};
402: $pwd =~ s:/[^/]*$::;
403: &newparser(\@pars,\$content_file_string,$pwd);
404:
405: my $safeeval = new Safe;
406: my $safehole = new Safe::Hole;
407: &init_safespace($target,$safeeval,$safehole,$safeinit);
408: #-------------------- Redefinition of the target in the case of compound target
409:
410: ($target, my @tenta) = split('&&',$target);
411:
412: my @stack = ();
413: my @parstack = ();
414: &initdepth;
415:
416: my $finaloutput = &inner_xmlparse($target,\@stack,\@parstack,\@pars,
417: $safeeval,\%style_for_target);
418: if ($ENV{'request.uri'}) {
419: &writeallows($ENV{'request.uri'});
420: }
421: return $finaloutput;
422: }
423:
424: sub htmlclean {
425: my ($raw,$full)=@_;
426:
427: my $tree = HTML::TreeBuilder->new;
428: $tree->ignore_unknown(0);
429:
430: $tree->parse($raw);
431:
432: my $output= $tree->as_HTML(undef,' ');
433:
434: $output=~s/\<(br|hr|img|meta|allow)([^\>\/]*)\>/\<$1$2 \/\>/gis;
435: $output=~s/\<\/(br|hr|img|meta|allow)\>//gis;
436: unless ($full) {
437: $output=~s/\<[\/]*(body|head|html)\>//gis;
438: }
439:
440: $tree = $tree->delete;
441:
442: return $output;
443: }
444:
445: sub inner_xmlparse {
446: my ($target,$stack,$parstack,$pars,$safeeval,$style_for_target)=@_;
447: my $finaloutput = '';
448: my $result;
449: my $token;
450: while ( $#$pars > -1 ) {
451: while ($token = $$pars['-1']->get_token) {
452: if (($token->[0] eq 'T') || ($token->[0] eq 'C') || ($token->[0] eq 'D') ) {
453: if ($metamode<1) {
454: $result=$token->[1];
455: }
456: } elsif ($token->[0] eq 'PI') {
457: if ($metamode<1) {
458: $result=$token->[2];
459: }
460: } elsif ($token->[0] eq 'S') {
461: # add tag to stack
462: push (@$stack,$token->[1]);
463: # add parameters list to another stack
464: push (@$parstack,&parstring($token));
465: &increasedepth($token);
466: if (exists $$style_for_target{$token->[1]}) {
467: if ($Apache::lonxml::redirection) {
468: $Apache::lonxml::outputstack['-1'] .=
469: &recurse($$style_for_target{$token->[1]},$target,$safeeval,
470: $style_for_target,@$parstack);
471: } else {
472: $finaloutput .= &recurse($$style_for_target{$token->[1]},$target,
473: $safeeval,$style_for_target,@$parstack);
474: }
475: } else {
476: $result = &callsub("start_$token->[1]", $target, $token, $stack,
477: $parstack, $pars, $safeeval, $style_for_target);
478: }
479: } elsif ($token->[0] eq 'E') {
480: #clear out any tags that didn't end
481: while ($token->[1] ne $$stack['-1'] && ($#$stack > -1)) {
482: &Apache::lonxml::warning("Unbalanced tags in resource $$stack['-1']");
483: &end_tag($stack,$parstack,$token);
484: }
485:
486: if (exists $$style_for_target{'/'."$token->[1]"}) {
487: if ($Apache::lonxml::redirection) {
488: $Apache::lonxml::outputstack['-1'] .=
489: &recurse($$style_for_target{'/'."$token->[1]"},
490: $target,$safeeval,$style_for_target,@$parstack);
491: } else {
492: $finaloutput .= &recurse($$style_for_target{'/'."$token->[1]"},
493: $target,$safeeval,$style_for_target,
494: @$parstack);
495: }
496:
497: } else {
498: $result = &callsub("end_$token->[1]", $target, $token, $stack,
499: $parstack, $pars,$safeeval, $style_for_target);
500: }
501: } else {
502: &Apache::lonxml::error("Unknown token event :$token->[0]:$token->[1]:");
503: }
504: #evaluate variable refs in result
505: if ($result ne "") {
506: if ( $#$parstack > -1 ) {
507: if ($Apache::lonxml::redirection) {
508: $Apache::lonxml::outputstack['-1'] .=
509: &Apache::run::evaluate($result,$safeeval,$$parstack['-1']);
510: } else {
511: $finaloutput .= &Apache::run::evaluate($result,$safeeval,
512: $$parstack['-1']);
513: }
514: } else {
515: $finaloutput .= &Apache::run::evaluate($result,$safeeval,'');
516: }
517: $result = '';
518: }
519: if ($token->[0] eq 'E') {
520: &end_tag($stack,$parstack,$token);
521: }
522: }
523: pop @$pars;
524: pop @Apache::lonxml::pwd;
525: }
526:
527: # if ($target eq 'meta') {
528: # $finaloutput.=&endredirection;
529: # }
530:
531: if (($ENV{'QUERY_STRING'}) && ($target eq 'web')) {
532: $finaloutput=&afterburn($finaloutput);
533: }
534: return $finaloutput;
535: }
536:
537: sub recurse {
538: my @innerstack = ();
539: my @innerparstack = ();
540: my ($newarg,$target,$safeeval,$style_for_target,@parstack) = @_;
541: my @pat = ();
542: &newparser(\@pat,\$newarg);
543: my $tokenpat;
544: my $partstring = '';
545: my $output='';
546: my $decls='';
547: while ( $#pat > -1 ) {
548: while ($tokenpat = $pat[$#pat]->get_token) {
549: if (($tokenpat->[0] eq 'T') || ($tokenpat->[0] eq 'C') || ($tokenpat->[0] eq 'D') ) {
550: if ($metamode<1) { $partstring=$tokenpat->[1]; }
551: } elsif ($tokenpat->[0] eq 'PI') {
552: if ($metamode<1) { $partstring=$tokenpat->[2]; }
553: } elsif ($tokenpat->[0] eq 'S') {
554: push (@innerstack,$tokenpat->[1]);
555: push (@innerparstack,&parstring($tokenpat));
556: &increasedepth($tokenpat);
557: $partstring = &callsub("start_$tokenpat->[1]", $target, $tokenpat,
558: \@innerstack, \@innerparstack, \@pat,
559: $safeeval, $style_for_target);
560: } elsif ($tokenpat->[0] eq 'E') {
561: #clear out any tags that didn't end
562: while ($tokenpat->[1] ne $innerstack[$#innerstack]
563: && ($#innerstack > -1)) {
564: &Apache::lonxml::warning("Unbalanced tags in resource $innerstack['-1']");
565: &end_tag(\@innerstack,\@innerparstack,$tokenpat);
566: }
567: $partstring = &callsub("end_$tokenpat->[1]", $target, $tokenpat,
568: \@innerstack, \@innerparstack, \@pat,
569: $safeeval, $style_for_target);
570: } else {
571: &Apache::lonxml::error("Unknown token event :$tokenpat->[0]:$tokenpat->[1]:");
572: }
573: #pass both the variable to the style tag, and the tag we
574: #are processing inside the <definedtag>
575: if ( $partstring ne "" ) {
576: if ( $#parstack > -1 ) {
577: if ( $#innerparstack > -1 ) {
578: $decls= $parstack[$#parstack].$innerparstack[$#innerparstack];
579: } else {
580: $decls= $parstack[$#parstack];
581: }
582: } else {
583: if ( $#innerparstack > -1 ) {
584: $decls=$innerparstack[$#innerparstack];
585: } else {
586: $decls='';
587: }
588: }
589: $output .= &Apache::run::evaluate($partstring,$safeeval,$decls);
590: $partstring = '';
591: }
592: if ($tokenpat->[0] eq 'E') { pop @innerstack;pop @innerparstack;
593: &decreasedepth($tokenpat);}
594: }
595: pop @pat;
596: pop @Apache::lonxml::pwd;
597: }
598: return $output;
599: }
600:
601: sub callsub {
602: my ($sub,$target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
603: my $currentstring='';
604: my $nodefault;
605: {
606: my $sub1;
607: no strict 'refs';
608: my $tag=$token->[1];
609: my $space=$Apache::lonxml::alltags{$tag};
610: if (!$space) {
611: $tag=~tr/A-Z/a-z/;
612: $sub=~tr/A-Z/a-z/;
613: $space=$Apache::lonxml::alltags{$tag}
614: }
615:
616: my $deleted=0;
617: $Apache::lonxml::curdepth=join('_',@Apache::lonxml::depthcounter);
618: if (($token->[0] eq 'S') && ($target eq 'modified')) {
619: $deleted=&Apache::edit::handle_delete($space,$target,$token,$tagstack,
620: $parstack,$parser,$safeeval,
621: $style);
622: }
623: if (!$deleted) {
624: if ($space) {
625: #&Apache::lonxml::debug("Calling sub $sub in $space $metamode<br />\n");
626: $sub1="$space\:\:$sub";
627: ($currentstring,$nodefault) = &$sub1($target,$token,$tagstack,
628: $parstack,$parser,$safeeval,
629: $style);
630: } else {
631: #&Apache::lonxml::debug("NOT Calling sub $sub in $space $metamode<br />\n");
632: if ($metamode <1) {
633: if (defined($token->[4]) && ($metamode < 1)) {
634: $currentstring = $token->[4];
635: } else {
636: $currentstring = $token->[2];
637: }
638: }
639: }
640: # &Apache::lonxml::debug("nodefalt:$nodefault:");
641: if ($currentstring eq '' && $nodefault eq '') {
642: if ($target eq 'edit') {
643: &Apache::lonxml::debug("doing default edit for $token->[1]");
644: if ($token->[0] eq 'S') {
645: $currentstring = &Apache::edit::tag_start($target,$token);
646: } elsif ($token->[0] eq 'E') {
647: $currentstring = &Apache::edit::tag_end($target,$token);
648: }
649: } elsif ($target eq 'modified') {
650: if ($token->[0] eq 'S') {
651: $currentstring = $token->[4];
652: $currentstring.=&Apache::edit::handle_insert();
653: } else {
654: $currentstring = $token->[2];
655: }
656: }
657: }
658: }
659: use strict 'refs';
660: }
661: return $currentstring;
662: }
663:
664: sub setup_globals {
665: my ($target)=@_;
666: $Apache::lonxml::registered = 0;
667: @Apache::lonxml::pwd=();
668: @Apache::lonxml::extlinks=();
669: if ($target eq 'meta') {
670: $Apache::lonxml::redirection = 0;
671: $Apache::lonxml::metamode = 1;
672: $Apache::lonxml::evaluate = 1;
673: $Apache::lonxml::import = 0;
674: } elsif ($target eq 'answer') {
675: $Apache::lonxml::redirection = 0;
676: $Apache::lonxml::metamode = 1;
677: $Apache::lonxml::evaluate = 1;
678: $Apache::lonxml::import = 1;
679: } elsif ($target eq 'grade') {
680: &startredirection;
681: $Apache::lonxml::metamode = 0;
682: $Apache::lonxml::evaluate = 1;
683: $Apache::lonxml::import = 1;
684: } elsif ($target eq 'modified') {
685: $Apache::lonxml::redirection = 0;
686: $Apache::lonxml::metamode = 0;
687: $Apache::lonxml::evaluate = 0;
688: $Apache::lonxml::import = 0;
689: } elsif ($target eq 'edit') {
690: $Apache::lonxml::redirection = 0;
691: $Apache::lonxml::metamode = 0;
692: $Apache::lonxml::evaluate = 0;
693: $Apache::lonxml::import = 0;
694: } else {
695: $Apache::lonxml::redirection = 0;
696: $Apache::lonxml::metamode = 0;
697: $Apache::lonxml::evaluate = 1;
698: $Apache::lonxml::import = 1;
699: }
700: }
701:
702: sub init_safespace {
703: my ($target,$safeeval,$safehole,$safeinit) = @_;
704: $safeeval->permit("entereval");
705: $safeeval->permit(":base_math");
706: $safeeval->permit("sort");
707: $safeeval->deny(":base_io");
708: $safehole->wrap(\&Apache::scripttag::xmlparse,$safeeval,'&xmlparse');
709: $safehole->wrap(\&Apache::lonnet::EXT,$safeeval,'&EXT');
710:
711: $safehole->wrap(\&Math::Cephes::asin,$safeeval,'&asin');
712: $safehole->wrap(\&Math::Cephes::acos,$safeeval,'&acos');
713: $safehole->wrap(\&Math::Cephes::atan,$safeeval,'&atan');
714: $safehole->wrap(\&Math::Cephes::sinh,$safeeval,'&sinh');
715: $safehole->wrap(\&Math::Cephes::cosh,$safeeval,'&cosh');
716: $safehole->wrap(\&Math::Cephes::tanh,$safeeval,'&tanh');
717: $safehole->wrap(\&Math::Cephes::asinh,$safeeval,'&asinh');
718: $safehole->wrap(\&Math::Cephes::acosh,$safeeval,'&acosh');
719: $safehole->wrap(\&Math::Cephes::atanh,$safeeval,'&atanh');
720: $safehole->wrap(\&Math::Cephes::erf,$safeeval,'&erf');
721: $safehole->wrap(\&Math::Cephes::erfc,$safeeval,'&erfc');
722: $safehole->wrap(\&Math::Cephes::j0,$safeeval,'&j0');
723: $safehole->wrap(\&Math::Cephes::j1,$safeeval,'&j1');
724: $safehole->wrap(\&Math::Cephes::jn,$safeeval,'&jn');
725: $safehole->wrap(\&Math::Cephes::jv,$safeeval,'&jv');
726: $safehole->wrap(\&Math::Cephes::y0,$safeeval,'&y0');
727: $safehole->wrap(\&Math::Cephes::y1,$safeeval,'&y1');
728: $safehole->wrap(\&Math::Cephes::yn,$safeeval,'&yn');
729: $safehole->wrap(\&Math::Cephes::yv,$safeeval,'&yv');
730: $safehole->wrap(\&Math::Random::random_beta,$safeeval,'&math_random_beta');
731: $safehole->wrap(\&Math::Random::random_chi_square,$safeeval,'&math_random_chi_square');
732: $safehole->wrap(\&Math::Random::random_exponential,$safeeval,'&math_random_exponential');
733: $safehole->wrap(\&Math::Random::random_f,$safeeval,'&math_random_f');
734: $safehole->wrap(\&Math::Random::random_gamma,$safeeval,'&math_random_gamma');
735: $safehole->wrap(\&Math::Random::random_multivariate_normal,$safeeval,'&math_random_multivariate_normal');
736: $safehole->wrap(\&Math::Random::random_multinomial,$safeeval,'&math_random_multinomial');
737: $safehole->wrap(\&Math::Random::random_noncentral_chi_square,$safeeval,'&math_random_noncentral_chi_square');
738: $safehole->wrap(\&Math::Random::random_noncentral_f,$safeeval,'&math_random_noncentral_f');
739: $safehole->wrap(\&Math::Random::random_normal,$safeeval,'&math_random_normal');
740: $safehole->wrap(\&Math::Random::random_permutation,$safeeval,'&math_random_permutation');
741: $safehole->wrap(\&Math::Random::random_permuted_index,$safeeval,'&math_random_permuted_index');
742: $safehole->wrap(\&Math::Random::random_uniform,$safeeval,'&math_random_uniform');
743: $safehole->wrap(\&Math::Random::random_poisson,$safeeval,'&math_random_poisson');
744: $safehole->wrap(\&Math::Random::random_uniform_integer,$safeeval,'&math_random_uniform_integer');
745: $safehole->wrap(\&Math::Random::random_negative_binomial,$safeeval,'&math_random_negative_binomial');
746: $safehole->wrap(\&Math::Random::random_binomial,$safeeval,'&math_random_binomial');
747: $safehole->wrap(\&Math::Random::random_seed_from_phrase,$safeeval,'&random_seed_from_phrase');
748: $safehole->wrap(\&Math::Random::random_set_seed_from_phrase,$safeeval,'&random_set_seed_from_phrase');
749: $safehole->wrap(\&Math::Random::random_get_seed,$safeeval,'&random_get_seed');
750: $safehole->wrap(\&Math::Random::random_set_seed,$safeeval,'&random_set_seed');
751:
752: #need to inspect this class of ops
753: # $safeeval->deny(":base_orig");
754: $safeinit .= ';$external::target="'.$target.'";';
755: my $rndseed;
756: my ($symb,$courseid,$domain,$name) = &Apache::lonxml::whichuser();
757: $rndseed=&Apache::lonnet::rndseed($symb,$courseid,$domain,$name);
758: $safeinit .= ';$external::randomseed='.$rndseed.';';
759: &Apache::run::run($safeinit,$safeeval);
760: }
761:
762: sub startredirection {
763: $Apache::lonxml::redirection++;
764: push (@Apache::lonxml::outputstack, '');
765: }
766:
767: sub endredirection {
768: if (!$Apache::lonxml::redirection) {
769: &Apache::lonxml::error("Endredirection was called, before a startredirection, perhaps you have unbalanced tags. Some debuging information:".join ":",caller);
770: return '';
771: }
772: $Apache::lonxml::redirection--;
773: pop @Apache::lonxml::outputstack;
774: }
775:
776: sub end_tag {
777: my ($tagstack,$parstack,$token)=@_;
778: pop(@$tagstack);
779: pop(@$parstack);
780: &decreasedepth($token);
781: }
782:
783: sub initdepth {
784: @Apache::lonxml::depthcounter=();
785: $Apache::lonxml::depth=-1;
786: $Apache::lonxml::olddepth=-1;
787: }
788:
789: sub increasedepth {
790: my ($token) = @_;
791: $Apache::lonxml::depth++;
792: $Apache::lonxml::depthcounter[$Apache::lonxml::depth]++;
793: if ($Apache::lonxml::depthcounter[$Apache::lonxml::depth]==1) {
794: $Apache::lonxml::olddepth=$Apache::lonxml::depth;
795: }
796: my $curdepth=join('_',@Apache::lonxml::depthcounter);
797: &Apache::lonxml::debug("s $Apache::lonxml::depth : $Apache::lonxml::olddepth : $curdepth : $token->[1]\n");
798: #print "<br />s $Apache::lonxml::depth : $Apache::lonxml::olddepth : $curdepth : $token->[1]\n";
799: }
800:
801: sub decreasedepth {
802: my ($token) = @_;
803: $Apache::lonxml::depth--;
804: if ($Apache::lonxml::depth<$Apache::lonxml::olddepth-1) {
805: $#Apache::lonxml::depthcounter--;
806: $Apache::lonxml::olddepth=$Apache::lonxml::depth+1;
807: }
808: if ( $Apache::lonxml::depth < -1) {
809: &Apache::lonxml::warning("Unbalanced tags in resource");
810: $Apache::lonxml::depth='-1';
811: }
812: my $curdepth=join('_',@Apache::lonxml::depthcounter);
813: &Apache::lonxml::debug("e $Apache::lonxml::depth : $Apache::lonxml::olddepth : $token->[1] : $curdepth\n");
814: #print "<br />e $Apache::lonxml::depth : $Apache::lonxml::olddepth : $token->[1] : $curdepth\n";
815: }
816:
817: sub get_all_text {
818:
819: my($tag,$pars)= @_;
820: my $depth=0;
821: my $token;
822: my $result='';
823: if ( $tag =~ m:^/: ) {
824: my $tag=substr($tag,1);
825: # &Apache::lonxml::debug("have:$tag:");
826: while (($depth >=0) && ($token = $pars->get_token)) {
827: # &Apache::lonxml::debug("e token:$token->[0]:$depth:$token->[1]");
828: if (($token->[0] eq 'T')||($token->[0] eq 'C')||($token->[0] eq 'D')) {
829: $result.=$token->[1];
830: } elsif ($token->[0] eq 'PI') {
831: $result.=$token->[2];
832: } elsif ($token->[0] eq 'S') {
833: if ($token->[1] eq $tag) { $depth++; }
834: $result.=$token->[4];
835: } elsif ($token->[0] eq 'E') {
836: if ( $token->[1] eq $tag) { $depth--; }
837: #skip sending back the last end tag
838: if ($depth > -1) { $result.=$token->[2]; } else {
839: $pars->unget_token($token);
840: }
841: }
842: }
843: } else {
844: while ($token = $pars->get_token) {
845: # &Apache::lonxml::debug("s token:$token->[0]:$depth:$token->[1]");
846: if (($token->[0] eq 'T')||($token->[0] eq 'C')||($token->[0] eq 'D')) {
847: $result.=$token->[1];
848: } elsif ($token->[0] eq 'PI') {
849: $result.=$token->[2];
850: } elsif ($token->[0] eq 'S') {
851: if ( $token->[1] eq $tag) {
852: $pars->unget_token($token); last;
853: } else {
854: $result.=$token->[4];
855: }
856: } elsif ($token->[0] eq 'E') {
857: $result.=$token->[2];
858: }
859: }
860: }
861: # &Apache::lonxml::debug("Exit:$result:");
862: return $result
863: }
864:
865: sub newparser {
866: my ($parser,$contentref,$dir) = @_;
867: push (@$parser,HTML::TokeParser->new($contentref));
868: $$parser['-1']->xml_mode('1');
869: if ( $dir eq '' ) {
870: push (@Apache::lonxml::pwd, $Apache::lonxml::pwd[$#Apache::lonxml::pwd]);
871: } else {
872: push (@Apache::lonxml::pwd, $dir);
873: }
874: # &Apache::lonxml::debug("pwd:$#Apache::lonxml::pwd");
875: # &Apache::lonxml::debug("pwd:$Apache::lonxml::pwd[$#Apache::lonxml::pwd]");
876: }
877:
878: sub parstring {
879: my ($token) = @_;
880: my $temp='';
881: map {
882: unless ($_=~/\W/) {
883: my $val=$token->[2]->{$_};
884: $val =~ s/([\%\@\\])/\\$1/g;
885: #if ($val =~ m/^[\%\@]/) { $val="\\".$val; }
886: $temp .= "my \$$_=\"$val\";"
887: }
888: } @{$token->[3]};
889: return $temp;
890: }
891:
892: sub writeallows {
893: unless ($#extlinks>=0) { return; }
894: my $thisurl='/res/'.&Apache::lonnet::declutter(shift);
895: if ($ENV{'httpref.'.$thisurl}) {
896: $thisurl=$ENV{'httpref.'.$thisurl};
897: }
898: my $thisdir=$thisurl;
899: $thisdir=~s/\/[^\/]+$//;
900: my %httpref=();
901: map {
902: $httpref{'httpref.'.
903: &Apache::lonnet::hreflocation($thisdir,$_)}=$thisurl;
904: } @extlinks;
905: @extlinks=();
906: &Apache::lonnet::appenv(%httpref);
907: }
908:
909: #
910: # Afterburner handles anchors, highlights and links
911: #
912: sub afterburn {
913: my $result=shift;
914: map {
915: my ($name, $value) = split(/=/,$_);
916: $value =~ tr/+/ /;
917: $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
918: if (($name eq 'highlight')||($name eq 'anchor')||($name eq 'link')) {
919: unless ($ENV{'form.'.$name}) {
920: $ENV{'form.'.$name}=$value;
921: }
922: }
923: } (split(/&/,$ENV{'QUERY_STRING'}));
924: if ($ENV{'form.highlight'}) {
925: map {
926: my $anchorname=$_;
927: my $matchthis=$anchorname;
928: $matchthis=~s/\_+/\\s\+/g;
929: $result=~s/($matchthis)/\<font color=\"red\"\>$1\<\/font\>/gs;
930: } split(/\,/,$ENV{'form.highlight'});
931: }
932: if ($ENV{'form.link'}) {
933: map {
934: my ($anchorname,$linkurl)=split(/\>/,$_);
935: my $matchthis=$anchorname;
936: $matchthis=~s/\_+/\\s\+/g;
937: $result=~s/($matchthis)/\<a href=\"$linkurl\"\>$1\<\/a\>/gs;
938: } split(/\,/,$ENV{'form.link'});
939: }
940: if ($ENV{'form.anchor'}) {
941: my $anchorname=$ENV{'form.anchor'};
942: my $matchthis=$anchorname;
943: $matchthis=~s/\_+/\\s\+/g;
944: $result=~s/($matchthis)/\<a name=\"$anchorname\"\>$1\<\/a\>/s;
945: $result.=(<<"ENDSCRIPT");
946: <script>
947: document.location.hash='$anchorname';
948: </script>
949: ENDSCRIPT
950: }
951: return $result;
952: }
953:
954: sub storefile {
955: my ($file,$contents)=@_;
956: if (my $fh=Apache::File->new('>'.$file)) {
957: print $fh $contents;
958: $fh->close();
959: }
960: }
961:
962: sub inserteditinfo {
963: my ($result,$filecontents)=@_;
964: unless ($filecontents) {
965: $filecontents=(<<SIMPLECONTENT);
966: <html>
967: <head>
968: <title>
969: Title of Document Goes Here
970: </title>
971: </head>
972: <body bgcolor="#FFFFFF">
973:
974: Body of Document Goes Here
975:
976: </body>
977: </html>
978: SIMPLECONTENT
979: }
980: my $editheader='<a href="#editsection">Edit below</a><hr />';
981: my $editfooter=(<<ENDFOOTER);
982: <hr />
983: <a name="editsection" />
984: <form method="post">
985: <textarea cols="80" rows="40" name="filecont">$filecontents</textarea>
986: <br />
987: <input type="submit" name="attemptclean"
988: value="Save and then attempt to clean HTML" />
989: <input type="submit" name="savethisfile" value="Save this" />
990: </form>
991: ENDFOOTER
992: $result=~s/(\<body[^\>]*\>)/$1$editheader/is;
993: $result=~s/(\<\/body\>)/$editfooter/is;
994: return $result;
995: }
996:
997: sub handler {
998: my $request=shift;
999:
1000: my $target='web';
1001:
1002: $Apache::lonxml::debug=0;
1003:
1004: if ($ENV{'browser.mathml'}) {
1005: $request->content_type('text/xml');
1006: } else {
1007: $request->content_type('text/html');
1008: }
1009:
1010: $request->send_http_header;
1011:
1012: return OK if $request->header_only;
1013:
1014:
1015: my $file=&Apache::lonnet::filelocation("",$request->uri);
1016: #
1017: # Edit action? Save file.
1018: #
1019: unless ($ENV{'request.state'} eq 'published') {
1020: if (($ENV{'form.savethisfile'}) || ($ENV{'form.attemptclean'})) {
1021: &storefile($file,$ENV{'form.filecont'});
1022: }
1023: }
1024: my %mystyle;
1025: my $result = '';
1026: my $filecontents=&Apache::lonnet::getfile($file);
1027: if ($filecontents == -1) {
1028: $result=(<<ENDNOTFOUND);
1029: <html>
1030: <head>
1031: <title>File not found</title>
1032: </head>
1033: <body bgcolor="#FFFFFF">
1034: <b>File not found: $file</b>
1035: </body>
1036: </html>
1037: ENDNOTFOUND
1038: $filecontents='';
1039: } else {
1040: unless ($ENV{'request.state'} eq 'published') {
1041: if ($ENV{'form.attemptclean'}) {
1042: $filecontents=&htmlclean($filecontents,1);
1043: }
1044: }
1045: $result = &Apache::lonxml::xmlparse($target,$filecontents,'',%mystyle);
1046: }
1047:
1048: #
1049: # Edit action? Insert editing commands
1050: #
1051: unless ($ENV{'request.state'} eq 'published') {
1052: $result=&inserteditinfo($result,$filecontents);
1053: }
1054:
1055: writeallows($request->uri);
1056:
1057: $request->print($result);
1058:
1059: return OK;
1060: }
1061:
1062: sub debug {
1063: if ($Apache::lonxml::debug eq 1) {
1064: print("DEBUG:".$_[0]."<br />\n");
1065: }
1066: }
1067:
1068: sub error {
1069: if (($Apache::lonxml::debug eq 1) || ($ENV{'request.state'} eq 'construct') ) {
1070: print "<b>ERROR:</b>".$_[0]."<br />\n";
1071: } else {
1072: print "<b>An Error occured while processing this resource. The instructor has been notified.</b> <br />";
1073: #notify author
1074: &Apache::lonmsg::author_res_msg($ENV{'request.filename'},$_[0]);
1075: #notify course
1076: if ( $ENV{'request.course.id'} ) {
1077: my $users=$ENV{'course.'.$ENV{'request.course.id'}.'.comment.email'};
1078: foreach my $user (split /\,/, $users) {
1079: ($user,my $domain) = split /:/, $user;
1080: &Apache::lonmsg::user_normal_msg($user,$domain,"Error in $ENV{'request.filename'}",$_[0]);
1081: }
1082: }
1083:
1084: #FIXME probably shouldn't have me get everything forever.
1085: &Apache::lonmsg::user_normal_msg('albertel','msu',"Error in $ENV{'request.filename'}",$_[0]);
1086: #&Apache::lonmsg::user_normal_msg('albertel','103',"Error in $ENV{'request.filename'}",$_[0]);
1087: }
1088: }
1089:
1090: sub warning {
1091: if ($ENV{'request.state'} eq 'construct') {
1092: print "<b>W</b>ARNING<b>:</b>".$_[0]."<br />\n";
1093: }
1094: }
1095:
1096: sub get_param {
1097: my ($param,$parstack,$safeeval,$context) = @_;
1098: if ( ! $context ) { $context = -1; }
1099: my $args ='';
1100: if ( $#$parstack > (-2-$context) ) { $args=$$parstack[$context]; }
1101: if ( $args =~ /my \$$param=\"/ ) {
1102: return &Apache::run::run("{$args;".'return $'.$param.'}',$safeeval); #'
1103: } else {
1104: return undef;
1105: }
1106: }
1107:
1108: sub get_param_var {
1109: my ($param,$parstack,$safeeval,$context) = @_;
1110: if ( ! $context ) { $context = -1; }
1111: my $args ='';
1112: if ( $#$parstack > (-2-$context) ) { $args=$$parstack[$context]; }
1113: if ( $args !~ /my \$$param=\"/ ) { return undef; }
1114: my $value=&Apache::run::run("{$args;".'return $'.$param.'}',$safeeval); #'
1115: if ($value =~ /^[\$\@\%]/) {
1116: return &Apache::run::run("return $value",$safeeval,1);
1117: } else {
1118: return $value;
1119: }
1120: }
1121:
1122: sub register_insert {
1123: my @data = split /\n/, &Apache::lonnet::getfile('/home/httpd/lonTabs/insertlist.tab');
1124: my $i;
1125: my $tagnum=0;
1126: my @order;
1127: for ($i=0;$i < $#data; $i++) {
1128: my $line = $data[$i];
1129: if ( $line =~ /^\#/ || $line =~ /^\s*\n/) { next; }
1130: if ( $line =~ /TABLE/ ) { last; }
1131: my ($tag,$descrip,$color,$function,$show) = split(/,/, $line);
1132: $insertlist{"$tagnum.tag"} = $tag;
1133: $insertlist{"$tagnum.description"} = $descrip;
1134: $insertlist{"$tagnum.color"} = $color;
1135: $insertlist{"$tagnum.function"} = $function;
1136: $insertlist{"$tagnum.show"}= $show;
1137: $insertlist{"$tag.num"}=$tagnum;
1138: $tagnum++;
1139: }
1140: $i++; #skipping TABLE line
1141: $tagnum = 0;
1142: for (;$i < $#data;$i++) {
1143: my $line = $data[$i];
1144: my ($mnemonic,@which) = split(/ +/,$line);
1145: my $tag = $insertlist{"$tagnum.tag"};
1146: for (my $j=0;$j <$#which;$j++) {
1147: if ( $which[$j] eq 'Y' ) {
1148: if ($insertlist{"$j.show"} ne 'no') {
1149: push(@{ $insertlist{"$tag.which"} },$j);
1150: }
1151: }
1152: }
1153: $tagnum++;
1154: }
1155: }
1156:
1157: sub description {
1158: my ($token)=@_;
1159: return $insertlist{$insertlist{"$token->[1].num"}.'.description'};
1160: }
1161:
1162: # ----------------------------------------------------------------- whichuser
1163: # returns a list of $symb, $courseid, $domain, $name that is correct for
1164: # calls to lonnet functions for this setup.
1165: # - looks for form.grade_ parameters
1166: sub whichuser {
1167: my $symb=&Apache::lonnet::symbread();
1168: my $courseid=$ENV{'request.course.id'};
1169: my $domain=$ENV{'user.domain'};
1170: my $name=$ENV{'user.name'};
1171: if (defined($ENV{'form.grade_symb'})) {
1172: my $tmp_courseid=$ENV{'form.grade_courseid'};
1173: my $allowed=&Apache::lonnet::allowed('mgr',$tmp_courseid);
1174: if ($allowed) {
1175: $symb=$ENV{'form.grade_symb'};
1176: $courseid=$ENV{'form.grade_courseid'};
1177: $domain=$ENV{'form.grade_domain'};
1178: $name=$ENV{'form.grade_username'};
1179: }
1180: }
1181: return ($symb,$courseid,$domain,$name);
1182: }
1183:
1184: 1;
1185: __END__
1186:
1187:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>