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