File:
[LON-CAPA] /
rat /
lonpage.pm
Revision
1.56:
download - view:
text,
annotated -
select for diffs
Mon Mar 22 20:37:06 2004 UTC (20 years, 6 months ago) by
sakharuk
Branches:
MAIN
CVS tags:
version_1_2_1,
version_1_2_0,
version_1_1_99_5,
version_1_1_99_4,
version_1_1_99_3,
version_1_1_99_2,
version_1_1_99_1,
version_1_1_99_0,
HEAD
Pages can be printed now but not for the problems marked as exam ones. There are still LaTeX conflicts between different LaTeX environments. The possibility to print pages was broken down due to use of form hash to pass data to ssi call (earlier it was done trough the ENV hash).
1: # The LearningOnline Network with CAPA
2: # Page Handler
3: #
4: # $Id: lonpage.pm,v 1.56 2004/03/22 20:37:06 sakharuk 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: # (TeX Content Handler
29: #
30: # YEAR=2000
31: # 05/29/00,05/30 Gerd Kortemeyer)
32: # 08/30,08/31,09/06,09/14,09/15,09/16,09/19,09/20,09/21,09/23,
33: # 10/02,10/10,10/14,10/16,10/18,10/19,10/31,11/6,11/14,11/16,
34: # YEAR=2001
35: # 08/13/01,08/30,10/1 Gerd Kortemeyer
36: # YEAR=2002
37: # 03/19 Gerd Kortemeyer
38: #
39: ###
40:
41: package Apache::lonpage;
42:
43: use strict;
44: use Apache::Constants qw(:common :http);
45: use Apache::lonnet();
46: use Apache::loncommon();
47: use Apache::lonxml();
48: use Apache::lonmenu;
49: use HTML::TokeParser;
50: use GDBM_File;
51: use Apache::lonsequence;
52:
53: # -------------------------------------------------------------- Module Globals
54: my %hash;
55: my @rows;
56:
57: # ------------------------------------------------------------------ Euclid gcd
58:
59: sub euclid {
60: my ($e,$f)=@_;
61: my $a; my $b; my $r;
62: if ($e>$f) { $b=$e; $r=$f; } else { $r=$e; $b=$f; }
63: while ($r!=0) {
64: $a=$b; $b=$r;
65: $r=$a%$b;
66: }
67: return $b;
68: }
69:
70: # ------------------------------------------------------------ Build page table
71:
72: sub tracetable {
73: my ($sofar,$rid,$beenhere)=@_;
74: my $further=$sofar;
75: unless ($beenhere=~/\&$rid\&/) {
76: $beenhere.=$rid.'&';
77:
78: if (defined($hash{'is_map_'.$rid})) {
79: if ((defined($hash{'map_start_'.$hash{'src_'.$rid}})) &&
80: (defined($hash{'map_finish_'.$hash{'src_'.$rid}}))) {
81: my $frid=$hash{'map_finish_'.$hash{'src_'.$rid}};
82: $sofar=
83: &tracetable($sofar,$hash{'map_start_'.$hash{'src_'.$rid}},
84: '&'.$frid.'&');
85: $sofar++;
86: if ($hash{'src_'.$frid}) {
87: my $brepriv=&Apache::lonnet::allowed('bre',$hash{'src_'.$frid});
88: if (($brepriv eq '2') || ($brepriv eq 'F')) {
89: if (defined($rows[$sofar])) {
90: $rows[$sofar].='&'.$frid;
91: } else {
92: $rows[$sofar]=$frid;
93: }
94: }
95: }
96: }
97: } else {
98: $sofar++;
99: if ($hash{'src_'.$rid}) {
100: my $brepriv=&Apache::lonnet::allowed('bre',$hash{'src_'.$rid});
101: if (($brepriv eq '2') || ($brepriv eq 'F')) {
102: if (defined($rows[$sofar])) {
103: $rows[$sofar].='&'.$rid;
104: } else {
105: $rows[$sofar]=$rid;
106: }
107: }
108: }
109: }
110:
111: if (defined($hash{'to_'.$rid})) {
112: my $mincond=1;
113: my $next='';
114: foreach (split(/\,/,$hash{'to_'.$rid})) {
115: my $thiscond=
116: &Apache::lonnet::directcondval($hash{'condid_'.$hash{'undercond_'.$_}});
117: if ($thiscond>=$mincond) {
118: if ($next) {
119: $next.=','.$_.':'.$thiscond;
120: } else {
121: $next=$_.':'.$thiscond;
122: }
123: if ($thiscond>$mincond) { $mincond=$thiscond; }
124: }
125: }
126: foreach (split(/\,/,$next)) {
127: my ($linkid,$condval)=split(/\:/,$_);
128: if ($condval>=$mincond) {
129: my $now=&tracetable($sofar,$hash{'goesto_'.$linkid},$beenhere);
130: if ($now>$further) { $further=$now; }
131: }
132: }
133:
134: }
135: }
136: return $further;
137: }
138:
139: # ================================================================ Main Handler
140:
141: sub handler {
142: my $r=shift;
143:
144: # ------------------------------------------- Set document type for header only
145:
146: if ($r->header_only) {
147: if ($ENV{'browser.mathml'}) {
148: &Apache::loncommon::content_type($r,'text/xml');
149: } else {
150: &Apache::loncommon::content_type($r,'text/html');
151: }
152: $r->send_http_header;
153: return OK;
154: }
155:
156: &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
157: ['forceselect','launch']);
158: my $number_of_columns = 1;
159: my $requrl=$r->uri;
160: my $target = $ENV{'form.grade_target'};
161: # &Apache::lonnet::logthis("Got a target of $target");
162: if ($target eq 'meta') {
163: &Apache::loncommon::content_type($r,'text/html');
164: $r->send_http_header;
165: return OK;
166: }
167: # ----------------------------------------------------------------- Tie db file
168: if (($ENV{'request.course.fn'}) && (!$ENV{'form.forceselect'})) {
169: my $fn=$ENV{'request.course.fn'};
170: if (-e "$fn.db") {
171: if (tie(%hash,'GDBM_File',"$fn.db",&GDBM_READER(),0640)) {
172: # ------------------------------------------------------------------- Hash tied
173: my $firstres=$hash{'map_start_'.$requrl};
174: my $lastres=$hash{'map_finish_'.$requrl};
175: if (($firstres) && ($lastres)) {
176: # ----------------------------------------------------------------- Render page
177:
178: @rows=();
179:
180: &tracetable(0,$firstres,'&');
181:
182: # ------------------------------------------------------------ Add to symb list
183:
184: my $i;
185: my %symbhash=();
186: for ($i=0;$i<=$#rows;$i++) {
187: if ($rows[$i]) {
188: my @colcont=split(/\&/,$rows[$i]);
189: foreach (@colcont) {
190: $symbhash{$hash{'src_'.$_}}='';
191: }
192: }
193: }
194: &Apache::lonnet::symblist($requrl,%symbhash);
195:
196: # ------------------------------------------------------------------ Page parms
197:
198: my $j;
199: my $lcm=1;
200: my $contents=0;
201: my $nforms=0;
202:
203: my %ssibody=();
204: my %ssibgcolor=();
205: my %ssitext=();
206: my %ssilink=();
207: my %ssivlink=();
208: my %ssialink=();
209:
210: my %metalink=();
211:
212: my %cellemb=();
213:
214: my $allscript='';
215: my $allmeta='';
216:
217: my $isxml=0;
218: my $xmlheader='';
219: my $xmlbody='';
220:
221: # --------------------------------------------- Get SSI output, post parameters
222:
223: for ($i=0;$i<=$#rows;$i++) {
224: if ($rows[$i]) {
225: $contents++;
226: my @colcont=split(/\&/,$rows[$i]);
227: $lcm*=($#colcont+1)/euclid($lcm,($#colcont+1));
228: foreach (@colcont) {
229: my $src=$hash{'src_'.$_};
230: $src=~/\.(\w+)$/;
231: $metalink{$_}=$src.'.meta';
232: $cellemb{$_}=Apache::loncommon::fileembstyle($1);
233: if ($cellemb{$_} eq 'ssi') {
234: # --------------------------------------------------------- This is an SSI cell
235: my $prefix=$_.'_';
236: my %posthash=('request.prefix' => $prefix);
237: if ($ENV{'form.grade_target'} eq 'tex') {
238: $posthash{'grade_target'}=$ENV{'form.grade_target'};
239: $posthash{'textwidth'}=$ENV{'form.textwidth'};
240: $posthash{'problem_split'}=$ENV{'form.problem_split'};
241: $posthash{'latex_type'}=$ENV{'form.latex_type'};
242: $posthash{'rndseed'}=$ENV{'form.rndseed'};
243: }
244: if (($ENV{'form.'.$prefix.'submit'})
245: || ($ENV{'form.all_submit'})) {
246: foreach (keys %ENV) {
247: if ($_=~/^form.$prefix/) {
248: my $name=$_;
249: $name=~s/^form.$prefix//;
250: $posthash{$name}=$ENV{$_};
251: }
252: }
253: }
254: my $output=Apache::lonnet::ssi($src,%posthash);
255: $output=~
256: s/\/\/ BEGIN LON\-CAPA Internal.+\/\/ END LON\-CAPA Internal\s//gs;
257: if ($target eq 'tex') {
258: $output =~ s/^([^&]+)\\begin{document}//;
259: $output =~ s/\\end{document}//;
260: $output = '\parbox{\minipagewidth}{ '.$output.' }';
261: #some additional cleanup necessary for LateX (due to limitations of table environment
262: $output =~ s/(\\vskip\s*\d+mm)\s*(\\\\)+/$1/g;
263: }
264: my $parser=HTML::TokeParser->new(\$output);
265: my $token;
266: my $thisdir=$src;
267: my $bodydef=0;
268: my $thisxml=0;
269: my @rlinks=();
270: if ($output=~/\?xml/) {
271: $isxml=1;
272: $thisxml=1;
273: $output=~
274: /((?:\<(?:\?xml|\!DOC|html)[^\>]*(?:\>|\>\]\>)\s*)+)\<body[^\>]*\>/si;
275: $xmlheader=$1;
276: }
277: while ($token=$parser->get_token) {
278: if ($token->[0] eq 'S') {
279: if ($token->[1] eq 'a') {
280: if ($token->[2]->{'href'}) {
281: $rlinks[$#rlinks+1]=
282: $token->[2]->{'href'};
283: }
284: } elsif ($token->[1] eq 'img') {
285: $rlinks[$#rlinks+1]=
286: $token->[2]->{'src'};
287: } elsif ($token->[1] eq 'embed') {
288: $rlinks[$#rlinks+1]=
289: $token->[2]->{'src'};
290: } elsif ($token->[1] eq 'base') {
291: $thisdir=$token->[2]->{'href'};
292: } elsif ($token->[1] eq 'body') {
293: $bodydef=1;
294: $ssibgcolor{$_}=$token->[2]->{'bgcolor'};
295: $ssitext{$_}=$token->[2]->{'text'};
296: $ssilink{$_}=$token->[2]->{'link'};
297: $ssivlink{$_}=$token->[2]->{'vlink'};
298: $ssialink{$_}=$token->[2]->{'alink'};
299: if ($thisxml) {
300: $xmlbody=$token->[4];
301: }
302: } elsif ($token->[1] eq 'meta') {
303: if ($token->[4] !~ m:/>$:) {
304: $allmeta.="\n".$token->[4].'</meta>';
305: } else {
306: $allmeta.="\n".$token->[4];
307: }
308: } elsif (($token->[1] eq 'script') &&
309: ($bodydef==0)) {
310: $allscript.="\n\n"
311: .$parser->get_text('/script');
312: }
313: }
314: }
315: if ($output=~/\<body[^\>]*\>(.*)/si) {
316: $output=$1;
317: }
318: $output=~s/\<\/body\>.*//si;
319: if ($output=~/\<form/si) {
320: $nforms++;
321: $output=~s/\<form[^\>]*\>//gsi;
322: $output=~s/\<\/form[^\>]*\>//gsi;
323: $output=~
324: s/\<((?:input|select|button|textarea)[^\>]+)name\s*\=\s*[\'\"]*([\w\.\:]+)[\'\"]*([^\>]*)\>/\<$1 name="$prefix$2" $3\>/gsi;
325: }
326: $thisdir=~s/\/[^\/]*$//;
327: foreach (@rlinks) {
328: unless (($_=~/^http:\/\//i) ||
329: ($_=~/^\//) ||
330: ($_=~/^javascript:/i) ||
331: ($_=~/^mailto:/i) ||
332: ($_=~/^\#/)) {
333: my $newlocation=
334: &Apache::lonnet::hreflocation($thisdir,$_);
335: $output=~s/(\"|\'|\=\s*)$_(\"|\'|\s|\>)/$1$newlocation$2/;
336: }
337: }
338: # -------------------------------------------------- Deal with Applet codebases
339: $output=~s/(\<applet[^\>]+)(codebase\=[^\S\>]+)*([^\>]*)\>/$1.($2?$2:' codebase="'.$thisdir.'"').$3.'>'/gei;
340: $ssibody{$_}=$output;
341: # ---------------------------------------------------------------- End SSI cell
342: }
343: }
344: }
345: }
346: unless ($contents) {
347: &Apache::loncommon::content_type($r,'text/html');
348: $r->send_http_header;
349: $r->print('<html><body>'.&mt('Empty page').'.</body></html>');
350: } else {
351: # ------------------------------------------------------------------ Build page
352:
353: # ---------------------------------------------------------------- Send headers
354: unless ($target eq 'tex') {
355: if ($isxml) {
356: &Apache::loncommon::content_type($r,'text/xml');
357: $r->send_http_header;
358: $r->print($xmlheader);
359: } else {
360: &Apache::loncommon::content_type($r,'text/html');
361: $r->send_http_header;
362: $r->print('<html>');
363: }
364: # ------------------------------------------------------------------------ Head
365: $r->print("\n<head>\n".$allmeta);
366: if ($allscript) {
367: $r->print("\n<script language='JavaScript'>\n".
368: $allscript."\n</script>\n");
369: }
370: $r->print(&Apache::lonmenu::registerurl(1,undef));
371: $r->print("\n</head>\n");
372: # ------------------------------------------------------------------ Start body
373: if ($isxml) {
374: $r->print($xmlbody);
375: } else {
376: $r->print(
377: '<body bgcolor="#FFFFFF" onLoad="'.&Apache::lonmenu::loadevents.
378: '" onUnload="'.&Apache::lonmenu::unloadevents.'">'.
379: &Apache::lonmenu::menubuttons(undef,$target,1)
380: );
381: }
382: # ------------------------------------------------------------------ Start form
383: if ($nforms) {
384: $r->print('<form method="post" action="'.
385: $requrl.'">');
386: }
387: } elsif ($target eq 'tex') {
388: $r->print('\documentclass{article}
389: \newcommand{\keephidden}[1]{}
390: \usepackage[dvips]{graphicx}
391: \usepackage{epsfig}
392: \usepackage{calc}
393: \usepackage{longtable}
394: \begin{document}');
395: }
396: # ----------------------------------------------------------------- Start table
397: if ($target eq 'tex') {
398: $r->print('\begin{longtable}INSERTTHEHEADOFLONGTABLE\endfirsthead\endhead ');
399: if ($number_of_columns le $lcm) {$number_of_columns=$lcm;};
400: } else {
401: $r->print('<table cols="'.$lcm.'" border="0">');
402: }
403: for ($i=0;$i<=$#rows;$i++) {
404: if ($rows[$i]) {
405: unless ($target eq 'tex') {
406: $r->print("\n<tr>");
407: }
408: my @colcont=split(/\&/,$rows[$i]);
409: my $avespan=$lcm/($#colcont+1);
410: for ($j=0;$j<=$#colcont;$j++) {
411: my $rid=$colcont[$j];
412: my $metainfo='<a name="'.
413: &Apache::lonnet::escape(&Apache::lonnet::declutter($hash{'src_'.$rid})).'" />'.
414: '<a href="'.
415: $metalink{$rid}.'" target="LONcatInfo">'.
416: '<img src="/adm/lonMisc/cat_button.gif" border=0>'.
417: '</img></a><a href="/adm/evaluate?postdata='.
418: &Apache::lonnet::escape(&Apache::lonnet::declutter($hash{'src_'.$rid}))
419: .'" target="LONcatInfo">'.
420: '<img src="/adm/lonMisc/eval_button.gif" border=0>'.
421: '</img></a>';
422: if (
423: ($hash{'src_'.$rid}=~/\.(problem|exam|quiz|assess|survey|form)$/) &&
424: (&Apache::lonnet::allowed('mgr',$ENV{'request.course.id'}))) {
425: my ($mapid,$resid)=split(/\./,$rid);
426: my $symb=
427: &Apache::lonnet::declutter($hash{'map_id_'.$mapid}).
428: '___'.$resid.'___'.
429: &Apache::lonnet::declutter($hash{'src_'.$rid});
430: $metainfo.=
431: '<a href="/adm/grades?symb='.&Apache::lonnet::escape($symb).
432: # '&command=submission" target="LONcatInfo">'.
433: '&command=submission">'.
434: '<img src="/adm/lonMisc/subm_button.gif" border=0>'.
435: '</img></a>'.
436: '<a href="/adm/grades?symb='.&Apache::lonnet::escape($symb).
437: # '&command=gradingmenu" target="LONcatInfo">'.
438: '&command=gradingmenu">'.
439: '<img src="/adm/lonMisc/pgrd_button.gif" border=0>'.
440: '</img></a>'.
441: '<a href="/adm/parmset?symb='.&Apache::lonnet::escape($symb).
442: # '" target="LONcatInfo">'.
443: '" >'.
444: '<img src="/adm/lonMisc/pprm_button.gif" border=0>'.
445: '</img></a>';
446: }
447: $metainfo.='<br></br>';
448: unless ($target eq 'tex') {
449: $r->print('<td colspan="'.$avespan.'"');
450: }
451: if ($cellemb{$rid} eq 'ssi') {
452: unless ($target eq 'tex') {
453: if ($ssibgcolor{$rid}) {
454: $r->print(' bgcolor="'.
455: $ssibgcolor{$rid}.'"');
456: }
457: $r->print('>'.$metainfo.'<font');
458:
459: if ($ssitext{$rid}) {
460: $r->print(' text="'.$ssitext{$rid}.'"');
461: }
462: if ($ssilink{$rid}) {
463: $r->print(' link="'.$ssilink{$rid}.'"');
464: }
465: if ($ssitext{$rid}) {
466: $r->print(' vlink="'.$ssivlink{$rid}.'"');
467: }
468: if ($ssialink{$rid}) {
469: $r->print(' alink="'.$ssialink{$rid}.'"');
470: }
471: $r->print('>');
472: }
473: $r->print($ssibody{$rid});
474: unless ($target eq 'tex') {
475: $r->print('</font>');
476: }
477: if ($ENV{'course.'.
478: $ENV{'request.course.id'}.
479: '.pageseparators'} eq 'yes') {
480: unless($target eq 'tex') {
481: $r->print('<hr />');
482: } else {
483: $r->print('\hline');
484: }
485: }
486: } elsif ($cellemb{$rid} eq 'img') {
487: $r->print('>'.$metainfo.'<img src="'.
488: $hash{'src_'.$rid}.'"></img>');
489: } elsif ($cellemb{$rid} eq 'emb') {
490: $r->print('>'.$metainfo.'<embed src="'.
491: $hash{'src_'.$rid}.'"></embed>');
492: }
493: unless ($target eq 'tex') {
494: $r->print('</td>');
495: } else {
496: for (my $incol=1;$incol<=$avespan;$incol++) {
497: $r->print(' & ');
498: }
499: }
500: }
501: unless ($target eq 'tex') {
502: $r->print('</tr>');
503: } else {
504: $r->print('REMOVETHEHEADOFLONGTABLE\\\\');
505: }
506: }
507: }
508: unless ($target eq 'tex') {
509: $r->print("\n</table>");
510: } else {
511: $r->print('\end{longtable}\strut');
512: }
513: # ---------------------------------------------------------------- Submit, etc.
514: if ($nforms) {
515: $r->print(
516: '<input name="all_submit" value="Submit All" type="'.
517: (($nforms>1)?'submit':'hidden').'"></input></form>');
518: }
519: unless ($target eq 'tex') {
520: $r->print('</body>'.&Apache::lonxml::xmlend());
521: } else {
522: $r->print('\end{document}'.$number_of_columns);
523: }
524: # -------------------------------------------------------------------- End page
525: }
526: # ------------------------------------------------------------- End render page
527: } else {
528: $r->content_type('text/html');
529: $r->send_http_header;
530: &Apache::lonsequence::viewmap($r,$requrl);
531: }
532: # ------------------------------------------------------------------ Untie hash
533: unless (untie(%hash)) {
534: &Apache::lonnet::logthis("<font color=blue>WARNING: ".
535: "Could not untie coursemap $fn (browse).</font>");
536: }
537: # -------------------------------------------------------------------- All done
538: return OK;
539: # ----------------------------------------------- Errors, hash could no be tied
540: }
541: }
542: }
543: $r->content_type('text/html');
544: $r->send_http_header;
545: &Apache::lonsequence::viewmap($r,$requrl);
546: return OK;
547: }
548:
549: 1;
550: __END__
551:
552: =head1 NAME
553:
554: Apache::lonpage - Page Handler
555:
556: =head1 SYNOPSIS
557:
558: Invoked by /etc/httpd/conf/srm.conf:
559:
560: <LocationMatch "^/res/.*\.page$>
561: SetHandler perl-script
562: PerlHandler Apache::lonpage
563: </LocationMatch>
564:
565: =head1 INTRODUCTION
566:
567: This module renders a .page resource.
568:
569: This is part of the LearningOnline Network with CAPA project
570: described at http://www.lon-capa.org.
571:
572: =head1 HANDLER SUBROUTINE
573:
574: This routine is called by Apache and mod_perl.
575:
576: =over 4
577:
578: =item *
579:
580: set document type for header only
581:
582: =item *
583:
584: tie db file
585:
586: =item *
587:
588: render page
589:
590: =item *
591:
592: add to symb list
593:
594: =item *
595:
596: page parms
597:
598: =item *
599:
600: Get SSI output, post parameters
601:
602: =item *
603:
604: SSI cell rendering
605:
606: =item *
607:
608: Deal with Applet codebases
609:
610: =item *
611:
612: Build page
613:
614: =item *
615:
616: send headers
617:
618: =item *
619:
620: start body
621:
622: =item *
623:
624: start form
625:
626: =item *
627:
628: start table
629:
630: =item *
631:
632: submit element, etc, render page, untie hash
633:
634: =back
635:
636: =head1 OTHER SUBROUTINES
637:
638: =over 4
639:
640: =item *
641:
642: euclid() : Euclid's method for determining the greatest common denominator.
643:
644: =item *
645:
646: tracetable() : Build page table.
647:
648: =back
649:
650: =cut
651:
652:
653:
654:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>