--- rat/lonpageflip.pm 2001/11/29 19:23:49 1.18 +++ rat/lonpageflip.pm 2006/02/07 19:46:08 1.63 @@ -2,7 +2,7 @@ # # Page flip handler # -# $Id: lonpageflip.pm,v 1.18 2001/11/29 19:23:49 www Exp $ +# $Id: lonpageflip.pm,v 1.63 2006/02/07 19:46:08 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -26,23 +26,12 @@ # # 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 Apache::Constants qw(:common :http REDIRECT); -use Apache::lonnet(); +use Apache::lonnet; use HTML::TokeParser; use GDBM_File; @@ -50,21 +39,54 @@ 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; } - if (&Apache::lonnet::allowed('bre',$hash{'src_'.$new})) { + if ($current) { $current.=','.$new; } else { $current=''.$new; } - } + return $current; } +sub fullmove { + my ($rid,$mapurl,$direction)=@_; + if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.'.db', + &GDBM_READER(),0640)) { + ($rid,$mapurl)=&move($rid,$mapurl,$direction); + untie(%hash); + } + 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; my $next=''; @@ -72,71 +94,110 @@ sub move { my $posnext=''; if ($direction eq 'forward') { # --------------------------------------------------------------------- Forward - if ($hash{'type_'.$rid} eq 'finish') { - $rid=$hash{'ids_/res/'.$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_'.$_}}); + foreach my $id (split(/\,/,$hash{'to_'.$rid})) { + my $thiscond= + &Apache::lonnet::directcondval($hash{'condid_'.$hash{'undercond_'.$id}}); 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_/res/'.$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 $thiscond= + &Apache::lonnet::directcondval($hash{'condid_'.$hash{'undercond_'.$id}}); + 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); + $mapurl=$hash{'map_id_'.(split(/\./,$next))[0]}; } } - return ($next,$mapurl); } +sub navlaunch { + my ($r)=@_; + &Apache::loncommon::content_type($r,'text/html'); + &Apache::loncommon::no_cache($r); + $r->send_http_header; + my $html=&Apache::lonxml::xmlbegin(); + $r->print("$html\n"); + $r->print(''. + &Apache::loncommon::bodytag('Launched')); + $r->print(<Goto first resource

+ +

Collapse external navigation window

+ENDNAV + $r->print(&Apache::loncommon::endbodytag().''); +} # ================================================================ Main Handler sub handler { @@ -145,104 +206,154 @@ 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; + if (tie(my %bighash,'GDBM_File',$env{'request.course.fn'}.'.db', + &GDBM_READER(),0640)) { + $furl=$bighash{'first_url'}; + untie(%bighash); + } + &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', - &GDBM_READER,0640)) { + 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='/res/'.(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', - &GDBM_READER,0640)) { + if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.'_symb.db', + &GDBM_READER(),0640)) { $last=$hash{'last_known'}; untie(%hash); } if ($last) { - $currenturl='/res/'.(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 ($mapurl,$mapnum,$thisurl)=split(/\_\_\_/,$position); - $cachehash{$thisurl}=$mapnum; + my ($startoutmap,$mapnum,$thisurl)=&Apache::lonnet::decode_symb($position); + $cachehash{$startoutmap}{$thisurl}=[$thisurl,$mapnum]; + $cachehash{$startoutmap}{'last_known'}= + [&Apache::lonnet::declutter($currenturl),$mapnum]; + # ============================================================ Tie the big hash - if (tie(%hash,'GDBM_File',$ENV{'request.course.fn'}.'.db', - &GDBM_READER,0640)) { - my $rid=$hash{'map_pc_/res/'.$mapurl}.'.'.$mapnum; + if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.'.db', + &GDBM_READER(),0640)) { + my $rid=$hash{'map_pc_'.&Apache::lonnet::clutter($startoutmap)}. + '.'.$mapnum; # ------------------------------------------------- Move forward, backward, etc - - ($next,$mapurl)=&move($rid,$mapurl,$direction); + my $endupmap; + ($next,$endupmap)=&move($rid,$startoutmap,$direction); # -------------------------------------- Do we have one and only one empty URL? my $safecount=0; - while (($next) && ($next!~/\,/) && (!$hash{'src_'.$next}) - && ($safecount<25)) { - ($next,$mapurl)=&move($next,$mapurl,$direction); + while (($next) && ($next!~/\,/) && + ((!$hash{'src_'.$next}) || + ((!$env{'request.role.adv'}) && $hash{'randomout_'.$next})) + && ($safecount<10000)) { + ($next,$endupmap)=&move($next,$endupmap,$direction); $safecount++; } +# We are now at at least one non-empty URL # ----------------------------------------------------- Check out possibilities if ($next) { @possibilities=split(/\,/,$next); if ($#possibilities==0) { # ---------------------------------------------- Only one possibility, redirect - $redirecturl=$hash{'src_'.$next}; - $cachehash{&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_'.$_}; - $cachehash - {&Apache::lonnet::declutter( - $multichoicehash - {'src_'.$_} - )} - =(split(/\./,$_))[1]; - } @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 @@ -251,68 +362,109 @@ sub handler { # ----------------- The program must come past this point to untie the big hash untie(%hash); # --------------------------------------------------------- Store position info - $cachehash{'last_direction'}=$direction; - $cachehash{'last_known'}=&Apache::lonnet::declutter($currenturl); - &Apache::lonnet::symblist($mapurl,%cachehash); + $cachehash{$startoutmap}{'last_direction'}=[$direction,'notasymb']; + foreach my $thismap (keys %cachehash) { + 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; + if ($redirectsymb ne '') { $url.='?symb='.&Apache::lonnet::escape($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 $bodytag= + &Apache::loncommon::bodytag('Multiple Resources'); $r->print(<Choose Next Location - -

LON-CAPA

-There are several possibilities of where to go next. +$bodytag +

$lt{'wherenext'}

-Please click on the the resource you intend to access: +$lt{'pick'}:

- + ENDSTART - map { + foreach my $id (@possibilities) { $r->print( ''); - } @possibilities; - $r->print('
TitleType
$lt{'titleheader'}$lt{'type'}
'. - $multichoicehash{'title_'.$_}. - ''.$multichoicehash{'type_'.$_}. + $multichoicehash{'src_'.$id}.'?symb=' . + Apache::lonnet::escape($multichoicehash{'symb_'.$id}).'">'. + $multichoicehash{'title_'.$id}. + ''.$multichoicehash{'type_'.$id}. '
'); - return OK; + } + $r->print(''); } else { - $r->print(<Choose Next Location - - -

Sorry!

-

Next resource could not be identified.

-

You probably are at the beginning or the end of the course.

- - + my $bodytag=&Apache::loncommon::bodytag('No Resource'); + $r->print(<No Resource +$bodytag +

$lt{'title'}

+

$lt{'explain'}

ENDNONE - return OK; - } - } + } + $r->print(< +
  • $lt{'back'}
  • +
  • $lt{'nav'}
  • + +ENDMENU + return OK; + } } else { # ------------------------------------------------- Problem, could not tie hash - $ENV{'user.error.msg'}="/adm/flip:bre:0:1:Course Data Missing"; + $env{'user.error.msg'}="/adm/flip:bre:0:1:Course Data Missing"; return HTTP_NOT_ACCEPTABLE; } } else { # ---------------------------------------- No, could not determine where we are - $r->internal_redirect('/adm/ambiguous'); + $r->internal_redirect('/adm/ambiguous'); } } else { # -------------------------- Class was not initialized or page fliped strangely - $ENV{'user.error.msg'}="/adm/flip:bre:0:0:Choose Course"; + $env{'user.error.msg'}="/adm/flip:bre:0:0:Choose Course"; return HTTP_NOT_ACCEPTABLE; } }