# The LearningOnline Network with CAPA # Routines to control the menu # # $Id: lonmenu.pm,v 1.74 2003/06/04 22:05:22 www Exp $ # # Copyright Michigan State University Board of Trustees # # This file is part of the LearningOnline Network with CAPA (LON-CAPA). # # LON-CAPA is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # LON-CAPA is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with LON-CAPA; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # /home/httpd/html/adm/gpl.txt # # http://www.lon-capa.org/ # # # There are two parameters controlling the action of this module: # # browser.interface - if this is 'textual', it overrides the second parameter # and goes to screen reader PDA mode # # environment.remote - if this is 'on', the routines controll the remote # control, otherwise they render the main window controls; ignored it # browser.interface is 'textual' # package Apache::lonmenu; use strict; use Apache::lonnet; use Apache::Constants qw(:common); use Apache::lonhtmlcommon(); use Apache::loncommon; use Apache::File; use vars qw(@desklines $readdesk); my @inlineremote; my $font; my $tabbg; my $pgbg; # ============================= This gets called at the top of the body section sub menubuttons { my $forcereg=shift; my $target =shift; my $registration=shift; my $navmaps=''; my $reloadlink=''; my $escurl=&Apache::lonnet::escape($ENV{'REQUEST_URI'}); my $escsymb=&Apache::lonnet::escape($ENV{'request.symb'}); if ($ENV{'browser.interface'} eq 'textual') { # Textual display only if ($ENV{'request.course.id'}) { $navmaps=(<Navigate Contents ENDNAV if (($ENV{'REQUEST_URI'}=~/^\/adm\//) && ($ENV{'REQUEST_URI'}!~/^\/adm\/wrapper\//) && ($ENV{'REQUEST_URI'}!~/^\/adm\/.*\/(smppg|bulletinboard|aboutme)(\?|$)/)) { my $escreload=&Apache::lonnet::escape('return:'); $reloadlink=(<Return to Last Location ENDRELOAD } } my $output=(< // BEGIN LON-CAPA Internal Main Menu $reloadlink $navmaps
ENDMAINMENU if ($registration) { $output.=&innerregister($forcereg,$target); } return $output."
"; } elsif ($ENV{'environment.remote'} eq 'off') { # Remote Control is switched off # figure out colors my $function='student'; if ($ENV{'request.role'}=~/^(cc|in|ta|ep)/) { $function='coordinator'; } if ($ENV{'request.role'}=~/^(su|dc|ad|li)/) { $function='admin'; } if (($ENV{'request.role'}=~/^(au|ca)/) || ($ENV{'REQUEST_URI'}=~/^(\/priv|\~)/)) { $function='author'; } my $domain=&Apache::loncommon::determinedomain(); $pgbg=&Apache::loncommon::designparm($function.'.pgbg',$domain); $tabbg=&Apache::loncommon::designparm($function.'.tabbg',$domain); $font=&Apache::loncommon::designparm($function.'.font',$domain); my $link=&Apache::loncommon::designparm($function.'.link',$domain); my $alink=&Apache::loncommon::designparm($function.'.alink',$domain); my $vlink=&Apache::loncommon::designparm($function.'.vlink',$domain); my $sidebg=&Apache::loncommon::designparm($function.'.sidebg',$domain); # Do we have a NAV link? if ($ENV{'request.course.id'}) { $navmaps=(< Navigate Contents ENDNAVREM if (($ENV{'REQUEST_URI'}=~/^\/adm\//) && ($ENV{'REQUEST_URI'}!~/^\/adm\/wrapper\//) && ($ENV{'REQUEST_URI'}!~/^\/adm\/.*\/(smppg|bulletinboard|aboutme)(\?|$)/)) { my $escreload=&Apache::lonnet::escape('return:'); $reloadlink=(< Return to Last Location ENDRELOAD } } my $reg=''; if ($registration) { $reg=&innerregister($forcereg,$target); } return (< // BEGIN LON-CAPA Internal $reloadlink $navmaps
Main Menu Launch Remote Control LON-CAPA
$reg ENDINLINEMENU } else { return ''; } } # ===== Early call to LONCAPAreg for long-running pages, preferably used right # ===== before $r->rflush() sub regflush { return ''; } # ====================================== This gets called in the header section sub registerurl { my $forcereg=shift; my $target = shift; my $result = ''; if ($ENV{'REQUEST_URI'} eq '/res/adm/pages/menu.html') { return ''; } my $force_title=''; if ($ENV{'request.state'} eq 'construct') { $force_title=&Apache::lonxml::display_title(); } if ($target eq 'edit') { $result .="\n"; } if (($ENV{'browser.interface'} eq 'textual') || ($ENV{'environment.remote'} eq 'off') || ((($ENV{'request.publicaccess'}) || (!&Apache::lonnet::is_on_map($ENV{'REQUEST_URI'}))) && (!$forcereg))) { my $loadfunction=''; my $inlineloadfunction=''; my $unloadfunction=''; unless (($ENV{'browser.interface'} eq 'textual') || ($ENV{'environment.remote'} eq 'off') || ($ENV{'request.publicaccess'})) { my $reopen=&Apache::lonmenu::reopenmenu(); $loadfunction='swmenu='.$reopen.'swmenu.windowloaded(self.name);window.focus();'; $inlineloadfunction=®flush(); $unloadfunction='swmenu='.$reopen.'swmenu.windowunloaded(self.name);'; } return $result.(< function LONCAPAreg() { $loadfunction } function LONCAPAstale() { $unloadfunction } $inlineloadfunction $force_title ENDFUNCTIONS } # Graphical display after login only if ($Apache::lonxml::registered && !$forcereg) { return ''; } $result.=&innerregister($forcereg,$target); return $result.$force_title; } # =========== This gets called in order to register a URL, both with the Remote # =========== and in the body of the document sub innerregister { my $forcereg=shift; my $target = shift; my $result = ''; if ($ENV{'REQUEST_URI'} eq '/res/adm/pages/menu.html') { return ''; } $Apache::lonxml::registered=1; my $textinter=($ENV{'browser.interface'} eq 'textual'); my $noremote=($ENV{'environment.remote'} eq 'off'); my $textual=($textinter || $noremote); @inlineremote=(); undef @inlineremote; my $reopen=&Apache::lonmenu::reopenmenu(); my $newmail=''; if ($noremote) { $newmail='
'; } if (($textual) && ($ENV{'request.symb'}) && ($ENV{'request.course.id'})) { my ($mapurl,$rid,$resurl)=split(/\_\_\_/,$ENV{'request.symb'}); $newmail.=$ENV{'course.'.$ENV{'request.course.id'}.'.description'}; my $maptitle=&Apache::lonnet::gettitle($mapurl); my $restitle=&Apache::lonnet::gettitle($resurl); if ($maptitle) { $newmail.=', '.$maptitle; } if ($restitle) { $newmail.=': '.$restitle; } $newmail.='   '; } if (&Apache::lonmsg::newmail()) { $newmail=($textual? 'You have new messages
': 'swmenu.setstatus("you have","messages");'); } if ($noremote) { $newmail.='
'; } my $timesync=($textual?'':'swmenu.syncclock(1000*'.time.');'); my $tablestart=($noremote?'':''); my $tableend=($noremote?'
':''); # ============================================================================= # ============================ This is for URLs that actually can be registered if (($ENV{'REQUEST_URI'}!~/^\/(res\/)*adm\//) || ($forcereg)) { # -- This applies to homework problems for users with grading privileges my $hwkadd=''; if ($ENV{'request.filename'}=~/\.(problem|exam|quiz|assess|survey|form)$/) { if (&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'})) { $hwkadd.=&switch('','',7,1,'subm.gif','view sub','missions', "gocmd('/adm/grades','submission')", 'View user submissions for this assessment resource'); } if (&Apache::lonnet::allowed('mgr',$ENV{'request.course.id'})) { $hwkadd.=&switch('','',7,2,'pgrd.gif','problem','grades', "gocmd('/adm/grades','gradingmenu')", 'Modify user grades for this assessment resource'); } if (&Apache::lonnet::allowed('opa',$ENV{'request.course.id'})) { $hwkadd.=&switch('','',7,3,'pparm.gif','problem','parms', "gocmd('/adm/parmset','set')", 'Modify deadlines, etc, for this assessment resource'); } } # -- End Homework ### ### Determine whether or not to display the 'cstr' button for this ### resource ### my $editbutton = ''; if ($ENV{'user.author'}) { if ($ENV{'request.role'}=~/^(ca|au)/) { # Set defaults for authors my ($top,$bottom) = ('con-','struct'); my $action = "go('/priv/".$ENV{'user.name'}."');"; my $cadom = $ENV{'request.role.domain'}; my $caname = $ENV{'user.name'}; my $desc = "Enter my resource construction space"; # Set defaults for co-authors if ($ENV{'request.role'} =~ /^ca/) { ($cadom,$caname)=($ENV{'request.role'}=~/(\w+)\/(\w+)$/); ($top,$bottom) = ('co con-','struct'); $action = "go('/priv/".$caname."');"; $desc = "Enter construction space as co-author"; } # Check that we are on the correct machine my $home = &Apache::lonnet::homeserver($caname,$cadom); if ($home eq $Apache::lonnet::perlvar{'lonHostID'}) { $editbutton=&switch ('','',6,1,$top,,$bottom,$action,$desc); } } ## ## Determine if user can edit url. ## my $cfile=''; my $cfuname=''; my $cfudom=''; if ($ENV{'request.filename'}) { my $file=&Apache::lonnet::declutter($ENV{'request.filename'}); $file=~s/^(\w+)\/(\w+)/\/priv\/$2/; # Chech that the user has permission to edit this resource ($cfuname,$cfudom)=&Apache::loncacc::constructaccess($file,$1); if (defined($cfudom)) { if (&Apache::lonnet::homeserver($cfuname,$cfudom) eq $Apache::lonnet::perlvar{'lonHostID'}) { $cfile=$file; } } } # Finally, turn the button on or off if ($cfile) { $editbutton=&switch ('','',6,1,'cstr.gif','edit','resource', "go('".$cfile."');","Edit this resource"); } elsif ($editbutton eq '') { $editbutton=&clear(6,1); } } ### ### # Prepare the rest of the buttons my $menuitems=(< // BEGIN LON-CAPA Internal $utility $timesync $newmail $tablestart $inlinebuttons $tableend $form ENDREGTEXT # Registered, graphical output } else { $result = (< // BEGIN LON-CAPA Internal var swmenu=null; function LONCAPAreg() { swmenu=$reopen; swmenu.windowloaded(self.name); swmenu.clearTimeout(swmenu.menucltim); $timesync $newmail $buttons swmenu.currentURL=window.location.pathname; swmenu.reloadURL=window.location.pathname+window.location.search; swmenu.currentSymb="$ENV{'request.symb'}"; swmenu.reloadSymb="$ENV{'request.symb'}"; swmenu.currentStale=0; $hwkadd $editbutton } function LONCAPAstale() { swmenu=$reopen swmenu.currentStale=1; if (swmenu.reloadURL!='' && swmenu.reloadURL!= null) { swmenu.switchbutton (3,1,'reload.gif','return','location','go(reloadURL)','Return to the last known location in the course sequence'); } swmenu.clearbut(7,1); swmenu.clearbut(7,2); swmenu.clearbut(7,3); swmenu.menucltim=swmenu.setTimeout( 'clearbut(2,1);clearbut(2,3);clearbut(8,1);clearbut(8,2);clearbut(8,3);'+ 'clearbut(9,1);clearbut(9,2);clearbut(9,3);clearbut(6,3);clearbut(6,1)', 2000); swmenu.windowunloaded(self.name); } // END LON-CAPA Internal ENDREGTHIS } # ============================================================================= } else { # ========================================== This can or will not be registered if ($textual) { # Not registered, textual $result= (< // BEGIN LON-CAPA Internal var swmenu=null; function LONCAPAreg() { swmenu=$reopen swmenu.windowloaded(self.name); $timesync swmenu.currentStale=1; swmenu.clearbut(2,1); swmenu.clearbut(2,3); swmenu.clearbut(8,1); swmenu.clearbut(8,2); swmenu.clearbut(8,3); if (swmenu.currentURL) { swmenu.switchbutton (3,1,'reload.gif','return','location','go(currentURL)'); } else { swmenu.clearbut(3,1); } } function LONCAPAstale() { swmenu=$reopen swmenu.windowunloaded(self.name); } // END LON-CAPA Internal ENDDONOTREGTHIS } # ============================================================================= } return $result; } sub loadevents() { if ($ENV{'REQUEST_URI'} eq '/res/adm/pages/menu.html') { return ''; } return 'LONCAPAreg();'; } sub unloadevents() { if ($ENV{'REQUEST_URI'} eq '/res/adm/pages/menu.html') { return ''; } return 'LONCAPAstale();'; } # ============================================================= Start up remote sub startupremote { my ($lowerurl)=@_; if (($ENV{'browser.interface'} eq 'textual') || ($ENV{'environment.remote'} eq 'off')) { return (''); } # # The Remote actually gets launched! # my $configmenu=&rawconfig(); my $esclowerurl=&Apache::lonnet::escape($lowerurl); return(< function wheelswitch() { if (window.status=='|') { window.status='/'; } else { if (window.status=='/') { window.status='-'; } else { if (window.status=='-') { window.status='\\\\'; } else { if (window.status=='\\\\') { window.status='|'; } } } } } // ---------------------------------------------------------- The wait function var canceltim; function wait() { if ((menuloaded==1) || (tim==1)) { window.status='Done.'; if (tim==0) { clearTimeout(canceltim); $configmenu window.location='$lowerurl'; } else { window.location='/adm/remote?action=collapse&url=$esclowerurl'; } } else { wheelswitch(); setTimeout('wait();',200); } } function main() { canceltim=setTimeout('tim=1;',30000); window.status='-'; wait(); } ENDREMOTESTARTUP } sub setflags() { return(< menuloaded=0; tim=0; ENDSETFLAGS } sub maincall() { if (($ENV{'browser.interface'} eq 'textual') || ($ENV{'environment.remote'} eq 'off')) { return ''; } return(< main(); ENDMAINCALL } # ================================================================= Reopen menu sub reopenmenu { if (($ENV{'browser.interface'} eq 'textual') || ($ENV{'environment.remote'} eq 'off')) { return ''; } my $menuname='LCmenu'.$Apache::lonnet::perlvar{'lonHostID'}; my $nothing = &Apache::lonhtmlcommon::javascript_nothing(); return('window.open('.$nothing.',"'.$menuname.'","",false);'); } # =============================================================== Open the menu sub open { my $returnval=''; if (($ENV{'browser.interface'} eq 'textual') || ($ENV{'environment.remote'} eq 'off')) { return ''; } my $menuname='LCmenu'.$Apache::lonnet::perlvar{'lonHostID'}; unless (shift eq 'unix') { # resizing does not work on linux because of virtual desktop sizes $returnval.=(<'.$returnval.''; } # ================================================================== Raw Config sub clear { my ($row,$col)=@_; unless (($ENV{'browser.interface'} eq 'textual') || ($ENV{'environment.remote'} eq 'off')) { return "\n".qq(window.status+='.';swmenu.clearbut($row,$col);); } else { $inlineremote[10*$row+$col]=''; return ''; } } # ============================================ Switch a button or create a link # Switch acts on the javascript that is executed when a button is clicked. # The javascript is usually similar to "go('/adm/roles')" or "cstrgo(..)". sub switch { my ($uname,$udom,$row,$col,$img,$top,$bot,$act,$desc,$nobreak)=@_; $act=~s/\$uname/$uname/g; $act=~s/\$udom/$udom/g; unless (($ENV{'browser.interface'} eq 'textual') || ($ENV{'environment.remote'} eq 'off')) { # Remote return "\n". qq(window.status+='.';swmenu.switchbutton($row,$col,"$img","$top","$bot","$act","$desc");); } elsif ($ENV{'browser.interface'} eq 'textual') { # Accessibility if ($nobreak==2) { return ''; } my $text=$top.' '.$bot; $text=~s/\- //; $inlineremote[10*$row+$col]="\n".($nobreak?' ':'
'). ''.$text.' '. ($nobreak?'':$desc); } else { # Inline Remote if ($nobreak==2) { return ''; } my $text=$top.' '.$bot; $text=~s/\- //; $inlineremote[10*$row+$col]="\n". ($nobreak==3?''.$text.''. ($nobreak?'':''.$desc.'').($nobreak!=1?'':''); } return ''; } sub secondlevel { my $output=''; my ($uname,$udom,$rol,$crs,$pub,$con,$row,$col,$prt,$img,$top,$bot,$act,$desc)=@_; if ($prt eq 'any') { $output.=switch($uname,$udom,$row,$col,$img,$top,$bot,$act,$desc); } elsif ($prt=~/^r(\w+)/) { if ($rol eq $1) { $output.=switch($uname,$udom,$row,$col,$img,$top,$bot,$act,$desc); } } return $output; } sub openmenu { my $menuname='LCmenu'.$Apache::lonnet::perlvar{'lonHostID'}; if (($ENV{'browser.interface'} eq 'textual') || ($ENV{'environment.remote'} eq 'off')) { return ''; } my $nothing = &Apache::lonhtmlcommon::javascript_nothing(); return "window.open(".$nothing.",'".$menuname."');"; } sub inlinemenu { @inlineremote=(); undef @inlineremote; &rawconfig(1); return join('',map { (defined($_)?$_:'') } @inlineremote); } sub rawconfig { my $textualoverride=shift; my $output=''; unless (($ENV{'browser.interface'} eq 'textual') || ($ENV{'environment.remote'} eq 'off')) { $output.= "window.status='Opening Remote Control';var swmenu=".&openmenu(). "\nwindow.status='Configuring Remote Control ';"; } else { unless ($textualoverride) { return ''; } } my $uname=$ENV{'user.name'}; my $udom=$ENV{'user.domain'}; my $adv=$ENV{'user.adv'}; my $author=$ENV{'user.author'}; my $crs=''; if ($ENV{'request.course.id'}) { $crs='/'.$ENV{'request.course.id'}; if ($ENV{'request.course.sec'}) { $crs.='_'.$ENV{'request.course.sec'}; } $crs=~s/\_/\//g; } my $pub=($ENV{'request.state'} eq 'published'); my $con=($ENV{'request.state'} eq 'construct'); my $rol=$ENV{'request.role'}; my $requested_domain = $ENV{'request.role.domain'}; foreach (@desklines) { my ($row,$col,$pro,$prt,$img,$top,$bot,$act,$desc)=split(/\:/,$_); $prt=~s/\$uname/$uname/g; $prt=~s/\$udom/$udom/g; $prt=~s/\$crs/$crs/g; $prt=~s/\$requested_domain/$requested_domain/g; if ($pro eq 'clear') { $output.=&clear($row,$col); } elsif ($pro eq 'any') { $output.=&secondlevel( $uname,$udom,$rol,$crs,$pub,$con,$row,$col,$prt,$img,$top,$bot,$act,$desc); } elsif ($pro eq 'smp') { unless ($adv) { $output.=&secondlevel( $uname,$udom,$rol,$crs,$pub,$con,$row,$col,$prt,$img,$top,$bot,$act,$desc); } } elsif ($pro eq 'adv') { if ($adv) { $output.=&secondlevel( $uname,$udom,$rol,$crs,$pub,$con,$row,$col,$prt,$img,$top,$bot,$act,$desc); } } elsif (($pro=~/p(\w+)/) && ($prt)) { if (&Apache::lonnet::allowed($1,$prt)) { $output.=switch($uname,$udom,$row,$col,$img,$top,$bot,$act,$desc); } } elsif ($pro eq 'course') { if ($ENV{'request.course.fn'}) { $output.=switch($uname,$udom,$row,$col,$img,$top,$bot,$act,$desc); } } elsif ($pro eq 'author') { if ($author) { if ((($prt eq 'rca') && ($ENV{'request.role'}=~/^ca/)) || (($prt eq 'rau') && ($ENV{'request.role'}=~/^au/))) { # Check that we are on the correct machine my $cadom=$requested_domain; my $caname=$ENV{'user.name'}; if ($prt eq 'rca') { ($cadom,$caname)= ($ENV{'request.role'}=~/(\w+)\/(\w+)$/); } $act =~ s/\$caname/$caname/g; my $home = &Apache::lonnet::homeserver($caname,$cadom); if ($home eq $Apache::lonnet::perlvar{'lonHostID'}) { $output.=switch($caname,$cadom, $row,$col,$img,$top,$bot,$act,$desc); } } } } } unless (($ENV{'browser.interface'} eq 'textual') || ($ENV{'environment.remote'} eq 'off')) { $output.="\nwindow.status='Synchronizing Time';swmenu.syncclock(1000*".time.");\nwindow.status='Remote Control Configured.';"; } return $output; } # ======================================================================= Close sub close { if (($ENV{'browser.interface'} eq 'textual') || ($ENV{'environment.remote'} eq 'off')) { return ''; } my $menuname='LCmenu'.$Apache::lonnet::perlvar{'lonHostID'}; return(< window.status='Accessing Remote Control'; menu=window.open("/adm/rat/empty.html","$menuname", "height=350,width=150,scrollbars=no,menubar=no"); window.status='Disabling Remote Control'; menu.active=0; menu.autologout=0; window.status='Closing Remote Control'; menu.close(); window.status='Done.'; ENDCLOSE } # ====================================================================== Footer sub footer { } sub utilityfunctions { unless (($ENV{'browser.interface'} eq 'textual') || ($ENV{'environment.remote'} eq 'off')) { return ''; } my $currenturl=$ENV{'REQUEST_URI'}; my $currentsymb=$ENV{'request.symb'}; return (< ENDSERVERFORM } # ================================================ Handler when called directly sub handler { my $r = shift; $r->content_type('text/html'); $r->send_http_header; return OK if $r->header_only; my $form=&serverform(); my $bodytag=&Apache::loncommon::bodytag('Main Menu'); my $function='student'; if ($ENV{'request.role'}=~/^(cc|in|ta|ep)/) { $function='coordinator'; } if ($ENV{'request.role'}=~/^(su|dc|ad|li)/) { $function='admin'; } if (($ENV{'request.role'}=~/^(au|ca)/) || ($ENV{'REQUEST_URI'}=~/^(\/priv|\~)/)) { $function='author'; } my $domain=&Apache::loncommon::determinedomain(); $pgbg=&Apache::loncommon::designparm($function.'.pgbg',$domain); $tabbg=&Apache::loncommon::designparm($function.'.tabbg',$domain); $font=&Apache::loncommon::designparm($function.'.font',$domain); # ---- Print the screen, pretent to be in text mode to generate text-based menu unless ($ENV{'brower.interface'} eq 'textual') { $ENV{'environment.remote'}='off'; } my $utility=&utilityfunctions(); $r->print(< LON-CAPA Main Menu $bodytag ENDHEADER $r->print(''.&inlinemenu().'
'.$form); $r->print(''); return OK; } # ================================================================ Main Program BEGIN { if (! defined($readdesk)) { { my $config=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}. '/mydesk.tab'); while (my $configline=<$config>) { $configline=(split(/\#/,$configline))[0]; $configline=~s/^\s+//; chomp($configline); if ($configline) { $desklines[$#desklines+1]=$configline; } } } $readdesk='done'; } } 1; __END__