--- rat/lonpageflip.pm 2002/08/18 21:45:41 1.29
+++ rat/lonpageflip.pm 2006/05/30 19:47:40 1.69
@@ -2,7 +2,7 @@
#
# Page flip handler
#
-# $Id: lonpageflip.pm,v 1.29 2002/08/18 21:45:41 www Exp $
+# $Id: lonpageflip.pm,v 1.69 2006/05/30 19:47:40 www Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -26,23 +26,13 @@
#
# http://www.lon-capa.org/
#
-# (Page Handler
-#
-# (TeX Content Handler
-#
-# 05/29/00,05/30 Gerd Kortemeyer)
-# 08/30,08/31,09/06,09/14,09/15,09/16,09/19,09/20,09/21,09/23,
-# 10/02 Gerd Kortemeyer)
-#
-# 10/03,10/05,10/06,10/07,10/09,10/10,10/11,10/16,10/17,
-# 11/14,11/16,
-# 10/01/01,05/01,05/28,07/05 Gerd Kortemeyer
package Apache::lonpageflip;
use strict;
+use LONCAPA;
use Apache::Constants qw(:common :http REDIRECT);
-use Apache::lonnet();
+use Apache::lonnet;
use HTML::TokeParser;
use GDBM_File;
@@ -50,6 +40,16 @@ use GDBM_File;
my %hash;
+sub cleanup {
+ if (tied(%hash)){
+ &Apache::lonnet::logthis('Cleanup pageflip: hash');
+ unless (untie(%hash)) {
+ &Apache::lonnet::logthis('Failed cleanup pageflip: hash');
+ }
+ }
+ return OK;
+}
+
sub addrid {
my ($current,$new,$condid)=@_;
unless ($condid) { $condid=0; }
@@ -65,7 +65,7 @@ sub addrid {
sub fullmove {
my ($rid,$mapurl,$direction)=@_;
- if (tie(%hash,'GDBM_File',$ENV{'request.course.fn'}.'.db',
+ if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.'.db',
&GDBM_READER(),0640)) {
($rid,$mapurl)=&move($rid,$mapurl,$direction);
untie(%hash);
@@ -73,6 +73,18 @@ sub fullmove {
return($rid,$mapurl);
}
+sub hash_src {
+ my ($id)=@_;
+ my ($mapid,$resid)=split(/\./,$id);
+ my $symb=&Apache::lonnet::encode_symb($hash{'map_id_'.$mapid},
+ $resid,$hash{'src_'.$id});
+ if ($hash{'encrypted_'.$id}) {
+ return (&Apache::lonenc::encrypted($hash{'src_'.$id}),
+ &Apache::lonenc::encrypted($symb));
+ }
+ return ($hash{'src_'.$id},$symb);
+}
+
sub move {
my ($rid,$mapurl,$direction)=@_;
my $startoutrid=$rid;
@@ -83,71 +95,83 @@ sub move {
my $posnext='';
if ($direction eq 'forward') {
# --------------------------------------------------------------------- Forward
- if ($hash{'type_'.$rid} eq 'finish') {
- $rid=$hash{'ids_'.&Apache::lonnet::clutter($mapurl)};
+ while ($hash{'type_'.$rid} eq 'finish') {
+ $rid=$hash{'ids_'.$hash{'map_id_'.(split(/\./,$rid))[0]}};
}
- map {
- my $thiscond=
- &Apache::lonnet::directcondval($hash{'condid_'.$hash{'undercond_'.$_}});
- if ($thiscond>=$mincond) {
+ foreach my $id (split(/\,/,$hash{'to_'.$rid})) {
+ my $condition= $hash{'conditions_'.$hash{'goesto_'.$id}};
+ my $rescond = &Apache::lonnet::docondval($condition);
+ my $linkcond = &Apache::lonnet::directcondval($hash{'condid_'.$hash{'undercond_'.$id}});
+ my $thiscond = ($rescond<$linkcond)?$rescond:$linkcond;
+ if ($thiscond>=$mincond) {
if ($posnext) {
- $posnext.=','.$_.':'.$thiscond;
+ $posnext.=','.$id.':'.$thiscond;
} else {
- $posnext=$_.':'.$thiscond;
+ $posnext=$id.':'.$thiscond;
}
if ($thiscond>$mincond) { $mincond=$thiscond; }
}
- } split(/\,/,$hash{'to_'.$rid});
- map {
- my ($linkid,$condval)=split(/\:/,$_);
+ }
+ foreach my $id (split(/\,/,$posnext)) {
+ my ($linkid,$condval)=split(/\:/,$id);
if ($condval>=$mincond) {
$next=&addrid($next,$hash{'goesto_'.$linkid},
$hash{'condid_'.$hash{'undercond_'.$linkid}});
}
- } split(/\,/,$posnext);
+ }
if ($hash{'is_map_'.$next}) {
# This jumps to the beginning of a new map (going down level)
if (
$hash{'map_type_'.$hash{'map_pc_'.$hash{'src_'.$next}}} eq 'sequence') {
$mapurl=$hash{'src_'.$next};
$next=$hash{'map_start_'.$hash{'src_'.$next}};
+ } elsif (
+# This jumps back up from an empty sequence, to a page up one level
+ $hash{'map_type_'.$hash{'map_pc_'.$hash{'src_'.$next}}} eq 'page') {
+ $mapurl=$hash{'map_id_'.(split(/\./,$next))[0]};
}
} elsif
((split(/\./,$startoutrid))[0]!=(split(/\./,$next))[0]) {
# This comes up from a map (coming up one level);
$mapurl=$hash{'map_id_'.(split(/\./,$next))[0]};
- }
+ }
} elsif ($direction eq 'back') {
# ------------------------------------------------------------------- Backwards
- if ($hash{'type_'.$rid} eq 'start') {
- $rid=$hash{'ids_'.&Apache::lonnet::clutter($mapurl)};
- }
- map {
- my $thiscond=
- &Apache::lonnet::directcondval($hash{'condid_'.$hash{'undercond_'.$_}});
- if ($thiscond>=$mincond) {
- if ($posnext) {
- $posnext.=','.$_.':'.$thiscond;
- } else {
- $posnext=$_.':'.$thiscond;
- }
- if ($thiscond>$mincond) { $mincond=$thiscond; }
- }
- } split(/\,/,$hash{'from_'.$rid});
- map {
- my ($linkid,$condval)=split(/\:/,$_);
- if ($condval>=$mincond) {
- $next=&addrid($next,$hash{'comesfrom_'.$linkid},
- $hash{'condid_'.$hash{'undercond_'.$linkid}});
- }
- } split(/\,/,$posnext);
+ while ($hash{'type_'.$rid} eq 'start') {
+ $rid=$hash{'ids_'.$hash{'map_id_'.(split(/\./,$rid))[0]}};
+ }
+ foreach my $id (split(/\,/,$hash{'from_'.$rid})) {
+ my $condition= $hash{'conditions_'.$hash{'comesfrom_'.$id}};
+ my $rescond = &Apache::lonnet::docondval($condition);
+ my $linkcond = &Apache::lonnet::directcondval($hash{'condid_'.$hash{'undercond_'.$id}});
+ my $thiscond = ($rescond<$linkcond)?$rescond:$linkcond;
+ if ($thiscond>=$mincond) {
+ if ($posnext) {
+ $posnext.=','.$id.':'.$thiscond;
+ } else {
+ $posnext=$id.':'.$thiscond;
+ }
+ if ($thiscond>$mincond) { $mincond=$thiscond; }
+ }
+ }
+ foreach my $id (split(/\,/,$posnext)) {
+ my ($linkid,$condval)=split(/\:/,$id);
+ if ($condval>=$mincond) {
+ $next=&addrid($next,$hash{'comesfrom_'.$linkid},
+ $hash{'condid_'.$hash{'undercond_'.$linkid}});
+ }
+ }
if ($hash{'is_map_'.$next}) {
# This jumps to the end of a new map (going down one level)
if (
$hash{'map_type_'.$hash{'map_pc_'.$hash{'src_'.$next}}} eq 'sequence') {
$mapurl=$hash{'src_'.$next};
$next=$hash{'map_finish_'.$hash{'src_'.$next}};
- }
+ } elsif (
+ $hash{'map_type_'.$hash{'map_pc_'.$hash{'src_'.$next}}} eq 'page') {
+# This jumps back up from an empty sequence, to a page up one level
+ $mapurl=$hash{'map_id_'.(split(/\./,$next))[0]};
+ }
} elsif
((split(/\./,$startoutrid))[0]!=(split(/\./,$next))[0]) {
# This comes back up from a map (going up one level);
@@ -157,6 +181,49 @@ sub move {
return ($next,$mapurl);
}
+sub navlaunch {
+ my ($r)=@_;
+ &Apache::loncommon::content_type($r,'text/html');
+ &Apache::loncommon::no_cache($r);
+ $r->send_http_header;
+ $r->print(&Apache::loncommon::start_page('Launched'));
+ $r->print(<
Collapse external navigation window
+ENDNAV + $r->print(&Apache::loncommon::end_page()); +} + +sub first_accessible_resource { + my $furl; + if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.'.db', + &GDBM_READER(),0640)) { + $furl=$hash{'first_url'}; + if (!&Apache::lonnet::allowed('bre',$furl)) { +# Wow, we cannot see this ... move forward to the next one that we can see + my ($newrid,$newmap)=&move($hash{'first_rid'},$hash{'first_mapurl'},'forward'); +# Build the new URL + my ($newresid,$newmapid)=split(/\./,$newrid); + my $symb=&Apache::lonnet::encode_symb($newmap,$newresid,$hash{'src_'.$newrid}); + $furl=&add_get_param($hash{'src_'.$newrid},{ 'symb' => $symb }); + if ($hash{'encrypted_'.$newrid}) { + $furl=&Apache::lonenc::encrypted($furl); + } + } + untie(%hash); + return $furl; + } else { + return '/adm/navmaps'; + } +} + # ================================================================ Main Handler sub handler { @@ -165,71 +232,106 @@ sub handler { # ------------------------------------------- Set document type for header only if ($r->header_only) { - $r->content_type('text/html'); - $r->send_http_header; - return OK; + &Apache::loncommon::content_type($r,'text/html'); + $r->send_http_header; + return OK; } my %cachehash=(); my $multichoice=0; my %multichoicehash=(); - my $redirecturl=''; + my ($redirecturl,$redirectsymb); my $next=''; my @possibilities=(); - if (($ENV{'form.postdata'})&&($ENV{'request.course.fn'})) { - $ENV{'form.postdata'}=~/(\w+)\:(.*)/; + &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['postdata']); + if (($env{'form.postdata'})&&($env{'request.course.fn'})) { + $env{'form.postdata'}=~/(\w+)\:(.*)/; my $direction=$1; my $currenturl=$2; - if ($direction eq 'return') { + if ($currenturl=~m|^/enc/|) { + $currenturl=&Apache::lonenc::unencrypted($currenturl); + } + $currenturl=~s/\.\d+\.(\w+)$/\.$1/; + if ($direction eq 'firstres') { + my $furl=&first_accessible_resource(); + &Apache::loncommon::content_type($r,'text/html'); + $r->header_out(Location => + 'http://'.$ENV{'HTTP_HOST'}.$furl); + + return REDIRECT; + } + if ($direction eq 'return' || $direction eq 'navlaunch') { # -------------------------------------------------------- Return to last known my $last; - if (tie(%hash,'GDBM_File',$ENV{'request.course.fn'}.'_symb.db', + if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.'_symb.db', &GDBM_READER(),0640)) { $last=$hash{'last_known'}; untie(%hash); } my $newloc; - if ($last) { - $newloc=&Apache::lonnet::clutter((split(/\_\_\_/,$last))[1]); + if (($last) && (tie(%hash,'GDBM_File',$env{'request.course.fn'}.'.db', + &GDBM_READER(),0640))) { + my ($murl,$id,$fn)=&Apache::lonnet::decode_symb($last); + $id=$hash{'map_pc_'.&Apache::lonnet::clutter($murl)}.'.'.$id; + $newloc=$hash{'src_'.$id}; + if ($newloc) { + if ($hash{'encrypted_'.$id}) { $newloc=&Apache::lonenc::encrypted($newloc); } + + } else { + $newloc='/adm/navmaps'; + } + untie %hash; } else { - $newloc='/adm/noidea.html'; + $newloc='/adm/navmaps'; } - $r->content_type('text/html'); - $r->header_out(Location => - 'http://'.$ENV{'HTTP_HOST'}.$newloc); - - return REDIRECT; + if ($newloc eq '/adm/navmaps' && $direction eq 'navlaunch') { + &navlaunch($r); + return OK; + } else { + &Apache::loncommon::content_type($r,'text/html'); + $r->header_out(Location => + 'http://'.$ENV{'HTTP_HOST'}.$newloc); + + return REDIRECT; + } } $currenturl=~s/^http\:\/\///; $currenturl=~s/^[^\/]+//; - unless (($currenturl=~/^\/res\//) || - ($currenturl=~/^\/adm\/wrapper\//)) { +# +# Is the current URL on the map? If not, start with last known URL +# + unless (&Apache::lonnet::is_on_map($currenturl)) { my $last; - if (tie(%hash,'GDBM_File',$ENV{'request.course.fn'}.'_symb.db', + if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.'_symb.db', &GDBM_READER(),0640)) { $last=$hash{'last_known'}; untie(%hash); } if ($last) { - $currenturl=&Apache::lonnet::clutter((split(/\_\_\_/,$last))[1]); + $currenturl=&Apache::lonnet::clutter((&Apache::lonnet::decode_symb($last))[2]); } else { - $r->content_type('text/html'); - $r->header_out(Location => - 'http://'.$ENV{'HTTP_HOST'}.'/adm/noidea.html'); - return REDIRECT; + if ($direction eq 'return') { + &Apache::loncommon::content_type($r,'text/html'); + $r->header_out(Location => + 'http://'.$ENV{'HTTP_HOST'}.'/adm/noidea.html'); + return REDIRECT; + } else { + &navlaunch($r); + return OK; + } } } # ------------------------------------------- Do we have any idea where we are? my $position; if ($position=Apache::lonnet::symbread($currenturl)) { # ------------------------------------------------------------------------- Yes - my ($startoutmap,$mapnum,$thisurl)=split(/\_\_\_/,$position); - $cachehash{$startoutmap}{$thisurl}=$mapnum; + my ($startoutmap,$mapnum,$thisurl)=&Apache::lonnet::decode_symb($position); + $cachehash{$startoutmap}{$thisurl}=[$thisurl,$mapnum]; $cachehash{$startoutmap}{'last_known'}= - &Apache::lonnet::declutter($currenturl); + [&Apache::lonnet::declutter($currenturl),$mapnum]; # ============================================================ Tie the big hash - if (tie(%hash,'GDBM_File',$ENV{'request.course.fn'}.'.db', + if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.'.db', &GDBM_READER(),0640)) { my $rid=$hash{'map_pc_'.&Apache::lonnet::clutter($startoutmap)}. '.'.$mapnum; @@ -240,7 +342,8 @@ sub handler { # -------------------------------------- Do we have one and only one empty URL? my $safecount=0; while (($next) && ($next!~/\,/) && - ((!$hash{'src_'.$next}) || ($hash{'randomout_'.$next})) + ((!$hash{'src_'.$next}) || + ((!$env{'request.role.adv'}) && $hash{'randomout_'.$next})) && ($safecount<10000)) { ($next,$endupmap)=&move($next,$endupmap,$direction); $safecount++; @@ -251,26 +354,27 @@ sub handler { @possibilities=split(/\,/,$next); if ($#possibilities==0) { # ---------------------------------------------- Only one possibility, redirect - $redirecturl=$hash{'src_'.$next}; - $cachehash{$endupmap} - {&Apache::lonnet::declutter($redirecturl)} - =(split(/\./,$next))[1]; + ($redirecturl,$redirectsymb)=&hash_src($next); + $cachehash{$endupmap}{$redirecturl}= + [$redirecturl,(split(/\./,$next))[1]]; } else { # ------------------------ There are multiple possibilities for a next resource $multichoice=1; - map { - $multichoicehash{'src_'.$_}=$hash{'src_'.$_}; - $multichoicehash{'title_'.$_}=$hash{'title_'.$_}; - $multichoicehash{'type_'.$_}=$hash{'type_'.$_}; - my ($choicemap,$choiceres)=split(/\./,$_); - $cachehash - {&Apache::lonnet::declutter($hash{'src_'.$choicemap})} - {&Apache::lonnet::declutter( - $multichoicehash - {'src_'.$_} - )} - =$choiceres; - } @possibilities; + foreach my $id (@possibilities) { + $multichoicehash{'src_'.$id}=$hash{'src_'.$id}; + $multichoicehash{'title_'.$id}=$hash{'title_'.$id}; + $multichoicehash{'type_'.$id}=$hash{'type_'.$id}; + (my $first, my $second) = $id =~ /(\d+).(\d+)/; + my $symbSrc = Apache::lonnet::declutter($hash{'src_'.$id}); + $multichoicehash{'symb_'.$id} = + Apache::lonnet::declutter($hash{'map_id_'.$first}.'___'. + $second.'___'.$symbSrc); + + my ($choicemap,$choiceres)=split(/\./,$id); + my $map=&Apache::lonnet::declutter($hash{'src_'.$choicemap}); + my $url=$multichoicehash{'src_'.$id}; + $cachehash{$map}{$url}=[$url,$choiceres]; + } } } else { # -------------------------------------------------------------- No place to go @@ -279,69 +383,111 @@ sub handler { # ----------------- The program must come past this point to untie the big hash untie(%hash); # --------------------------------------------------------- Store position info - $cachehash{$startoutmap}{'last_direction'}=$direction; + $cachehash{$startoutmap}{'last_direction'}=[$direction,'notasymb']; foreach my $thismap (keys %cachehash) { - &Apache::lonnet::symblist($thismap,%{$cachehash{$thismap}}); + my $mapnum=$cachehash{$thismap}->{'mapnum'}; + delete($cachehash{$thismap}->{'mapnum'}); + &Apache::lonnet::symblist($thismap, + %{$cachehash{$thismap}}); } # ============================================== Do not return before this line if ($redirecturl) { # ----------------------------------------------------- There is a URL to go to - $r->content_type('text/html'); - $r->header_out(Location => - 'http://'.$ENV{'HTTP_HOST'}.$redirecturl); + if ($direction eq 'forward') { + &Apache::lonnet::linklog($currenturl,$redirecturl); + } + if ($direction eq 'back') { + &Apache::lonnet::linklog($redirecturl,$currenturl); + } +# ------------------------------------------------- Check for critical messages + if ((time-$env{'user.criticalcheck.time'})>300) { + my @what=&Apache::lonnet::dump + ('critical',$env{'user.domain'}, + $env{'user.name'}); + if ($what[0]) { + if (($what[0] ne 'con_lost') && + ($what[0]!~/^error\:/)) { + $redirecturl='/adm/email?critical=display'; + $redirectsymb=''; + } + } + &Apache::lonnet::appenv('user.criticalcheck.time'=>time); + } + + &Apache::loncommon::content_type($r,'text/html'); + my $url='http://'.$ENV{'HTTP_HOST'}.$redirecturl; + $url = &add_get_param($url, { 'symb' => $redirectsymb}); + $r->header_out(Location => $url); return REDIRECT; } else { # --------------------------------------------------------- There was a problem - $r->content_type('text/html'); + &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; + my %lt=&Apache::lonlocal::texthash('title' => 'End of Sequence', + 'explain' => + 'You have reached the end of the sequence of materials.', + 'back' => 'Go Back', + 'nav' => 'Navigate Course Content', + 'wherenext' => + 'There are several possibilities of where to go next', + 'pick' => + 'Please click on the the resource you intend to access', + 'titleheader' => 'Title', + 'type' => 'Type'); if ($#possibilities>0) { + my $start_page= + &Apache::loncommon::start_page('Multiple Resources'); $r->print(<-Please click on the the resource you intend to access: +$lt{'pick'}:
Title | Type | |
---|---|---|
$lt{'titleheader'} | $lt{'type'} | |
'. - $multichoicehash{'title_'.$_}. - ' | '.$multichoicehash{'type_'.$_}. + &add_get_param($multichoicehash{'src_'.$id}, + {'symb' => + $multichoicehash{'symb_'.$id}, + }).'">'. + $multichoicehash{'title_'.$id}. + ' | '.$multichoicehash{'type_'.$id}. ' |