# The LearningOnline Network with CAPA
# Routines to control the menu
#
# $Id: lonmenu.pm,v 1.369.2.46 2013/08/13 14:17:37 raeburn 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/
#
#
=head1 NAME
Apache::lonmenu
=head1 SYNOPSIS
Loads contents of /home/httpd/lonTabs/mydesk.tab,
used to generate inline menu, and Main Menu page.
This is part of the LearningOnline Network with CAPA project
described at http://www.lon-capa.org.
=head1 GLOBAL VARIABLES
=over
=item @desklines
Each element of this array contains a line of mydesk.tab that doesn't start with
cat, prim or scnd.
It gets filled in the BEGIN block of this module.
=item %category_names
The keys of this hash are the abbreviations used in mydesk.tab in those lines that
start with cat, the values are strings representing titles.
It gets filled in the BEGIN block of this module.
=item %category_members
TODO
=item %category_positions
The keys of this hash are the abbreviations used in mydesk.tab in those lines that
start with cat, its values are position vectors (column, row).
It gets filled in the BEGIN block of this module.
=item $readdesk
Indicates that mydesk.tab has been read.
It is set to 'done' in the BEGIN block of this module.
=item @primary_menu
The elements of this array reference arrays that are made up of the components
of those lines of mydesk.tab that start with prim:.
It is used by primary_menu() to generate the corresponding menu.
It gets filled in the BEGIN block of this module.
=item %primary_sub_menu
The keys of this hash reference are the names of items in the primary_menu array
which have sub-menus. For each key, the corresponding value is a reference to
an array containing components extracted from lines in mydesk.tab which begin
with primsub:.
This hash, which is used by primary_menu to generate sub-menus, is populated in
the BEGIN block.
=item @secondary_menu
The elements of this array reference arrays that are made up of the components
of those lines of mydesk.tab that start with scnd.
It is used by secondary_menu() to generate the corresponding menu.
It gets filled in the BEGIN block of this module.
=back
=head1 SUBROUTINES
=over
=item prep_menuitems(\@menuitem)
This routine wraps a menuitem in proper HTML. It is used by primary_menu() and
secondary_menu().
=item primary_menu()
This routine evaluates @primary_menu and returns a two item array,
with the array elements containing XHTML for the left and right sides of
the menu that contains the following links: About, Message, Roles, Help, Logout
@primary_menu is filled within the BEGIN block of this module with
entries from mydesk.tab
=item secondary_menu()
Same as primary_menu() but operates on @secondary_menu.
=item create_submenu()
Creates XHTML for unordered list of sub-menu items which belong to a
particular top-level menu item. Uses hover pseudo class in css to display
dropdown list when mouse hovers over top-level item. Support for IE6
(no hover psuedo class) via LC_hoverable class for
tag for top-
level item, which employs jQuery to handle behavior on mouseover.
Inputs: 4 - (a) link and (b) target for anchor href in top level item,
(c) title for text wrapped by anchor tag in top level item.
(d) reference to array of arrays of sub-menu items.
=item innerregister()
This gets called in order to register a URL in the body of the document
=item loadevents()
=item unloadevents()
=item startupremote()
=item setflags()
=item maincall()
=item load_remote_msg()
=item get_menu_name()
=item reopenmenu()
=item open()
Open the menu
=item clear()
=item switch()
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(..)".
=item secondlevel()
=item openmenu()
=item inlinemenu()
=item rawconfig()
=item utilityfunctions()
Output from this routine is a number of javascript functions called by
items in the inline menu, and in some cases items in the Main Menu page.
=item serverform()
=item constspaceform()
=item get_nav_status()
=item hidden_button_check()
=item roles_selector()
=item jump_to_role()
=back
=cut
package Apache::lonmenu;
use strict;
use Apache::lonnet;
use Apache::lonhtmlcommon();
use Apache::loncommon();
use Apache::lonenc();
use Apache::lonlocal;
use Apache::lonmsg();
use LONCAPA qw(:DEFAULT :match);
use HTML::Entities();
use Apache::lonwishlist();
use vars qw(@desklines %category_names %category_members %category_positions
$readdesk @primary_menu %primary_submenu @secondary_menu %secondary_submenu);
my @inlineremote;
sub prep_menuitem {
my ($menuitem) = @_;
return '' unless(ref($menuitem) eq 'ARRAY');
my $link;
if ($$menuitem[1]) { # graphical Link
$link = "";
} else { # textual Link
$link = &mt($$menuitem[3]);
}
return '
|;
}
# primary_menu() evaluates @primary_menu and returns a two item array,
# with the array elements containing XHTML for the left and right sides of
# the menu that contains the following links:
# Personal, About, Message, Roles, Help, Logout
# @primary_menu is filled within the BEGIN block of this module with
# entries from mydesk.tab
sub primary_menu {
my %menu;
# each element of @primary contains following array:
# (link url, icon path, alt text, link text, condition, position)
my $public;
if ((($env{'user.name'} eq 'public') && ($env{'user.domain'} eq 'public'))
|| (($env{'user.name'} eq '') && ($env{'user.domain'} eq ''))) {
$public = 1;
}
foreach my $menuitem (@primary_menu) {
# evaluate conditions
next if ref($menuitem) ne 'ARRAY'; #
next if $$menuitem[4] eq 'nonewmsg' # show links depending on
&& &Apache::lonmsg::mynewmail(); # whether a new msg
next if $$menuitem[4] eq 'newmsg' # arrived or not
&& !&Apache::lonmsg::mynewmail(); #
next if $$menuitem[4] !~ /public/ ##we've a public user,
&& $public; ##who should not see all
##links
next if $$menuitem[4] eq 'onlypublic'# hide links which are
&& !$public; # only visible to public
# users
next if $$menuitem[4] eq 'roles' ##show links depending on
&& &Apache::loncommon::show_course(); ##term 'Courses' or
next if $$menuitem[4] eq 'courses' ##'Roles' wanted
&& !&Apache::loncommon::show_course(); ##
my $title = $menuitem->[3];
my $position = $menuitem->[5];
if ($position eq '') {
$position = 'right';
}
if (defined($primary_submenu{$title})) {
my ($link,$target);
if ($menuitem->[0] ne '') {
$link = $menuitem->[0];
$target = '_top';
} else {
$link = '#';
}
my @primsub;
if (ref($primary_submenu{$title}) eq 'ARRAY') {
foreach my $item (@{$primary_submenu{$title}}) {
next if (($item->[2] eq 'wishlist') && (!$env{'user.adv'}));
next if ((($item->[2] eq 'portfolio') ||
($item->[2] eq 'blog')) &&
(!&Apache::lonnet::usertools_access('','',$item->[2],
undef,'tools')));
push(@primsub,$item);
}
if (@primsub > 0) {
$menu{$position} .= &create_submenu($link,$target,$title,\@primsub,1);
} elsif ($link) {
$menu{$position} .= '
';
}
}
} elsif ($$menuitem[3] eq 'Help') { # special treatment for helplink
if ($public) {
my $origmail = $Apache::lonnet::perlvar{'lonSupportEMail'};
my $defdom = &Apache::lonnet::default_login_domain();
my $to = &Apache::loncommon::build_recipient_list(undef,
'helpdeskmail',
$defdom,$origmail);
if ($to ne '') {
$menu{$position} .= &prep_menuitem($menuitem);
}
} else {
$menu{$position} .= '
'.&Apache::loncommon::top_nav_help('Help').'
';
}
} else {
$menu{$position} .= prep_menuitem($menuitem);
}
}
return ("$menu{'left'}",
"$menu{'right'}");
}
#returns hashref {user=>'',dom=>''} containing:
# own name, domain if user is au
# name, domain of parent author if user is ca or aa
#empty return if user is not an author or not on homeserver
#
#TODO this should probably be moved somewhere more central
#since it can be used by different parts of the system
sub getauthor{
return unless $env{'request.role'}=~/^(ca|aa|au)/; #nothing to do if user isn't some kind of author
#co- or assistent author?
my ($dom, $user) = ($env{'request.role'} =~ /^(?:ca|aa)\.\/($match_domain)\/($match_username)$/)
? ($1, $2) #domain, username of the parent author
: @env{ ('request.role.domain', 'user.name') }; #own domain, username
# current server == home server?
my $home = &Apache::lonnet::homeserver($user,$dom);
foreach (&Apache::lonnet::current_machine_ids()){
return {user => $user, dom => $dom} if $_ eq $home;
}
# if wrong server
return;
}
sub secondary_menu {
my $menu;
my $crstype = &Apache::loncommon::course_type();
my $crs_sec = $env{'request.course.id'} . ($env{'request.course.sec'}
? "/$env{'request.course.sec'}"
: '');
my $canedit = &Apache::lonnet::allowed('mdc', $env{'request.course.id'});
my $canviewroster = $env{'course.'.$env{'request.course.id'}.'.student_classlist_view'};
if ($canviewroster eq 'disabled') {
undef($canviewroster);
}
my $canviewgrps = &Apache::lonnet::allowed('vcg', $crs_sec);
my $canmodifyuser = &Apache::lonnet::allowed('cst', $crs_sec);
my $canviewwnew = &Apache::lonnet::allowed('whn', $crs_sec);
my $canmodpara = &Apache::lonnet::allowed('opa', $crs_sec);
my $canvgr = &Apache::lonnet::allowed('vgr', $crs_sec);
my $canmgr = &Apache::lonnet::allowed('mgr', $crs_sec);
my $author = &getauthor();
my ($cdom,$cnum,$showsyllabus,$showfeeds,$showresv);
if ($env{'request.course.id'}) {
$cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
$cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
unless ($canedit) {
unless (&Apache::lonnet::is_on_map("public/$cdom/$cnum/syllabus")) {
if (($env{'course.'.$env{'request.course.id'}.'.externalsyllabus'}) ||
($env{'course.'.$env{'request.course.id'}.'.uploadedsyllabus'}) ||
($env{'course.'.$env{'request.course.id'}.'.updatedsyllabus'}) ||
($env{'request.course.syllabustime'})) {
$showsyllabus = 1;
}
}
if ($env{'request.course.feeds'}) {
$showfeeds = 1;
}
}
unless ($canmgr) {
my %slots = &Apache::lonnet::get_course_slots($cnum,$cdom);
if (keys(%slots) > 0) {
$showresv = 1;
}
}
}
my ($canmodifycoauthor);
if ($env{'request.role'} eq "au./$env{'user.domain'}/") {
my $extent = "$env{'user.domain'}/$env{'user.name'}";
if ((&Apache::lonnet::allowed('cca',$extent)) ||
(&Apache::lonnet::allowed('caa',$extent))) {
$canmodifycoauthor = 1;
}
}
my %groups = &Apache::lonnet::get_active_groups(
$env{'user.domain'}, $env{'user.name'},
$env{'course.' . $env{'request.course.id'} . '.domain'},
$env{'course.' . $env{'request.course.id'} . '.num'});
my ($roleswitcher_js,$roleswitcher_form);
foreach my $menuitem (@secondary_menu) {
# evaluate conditions
next if ref($menuitem) ne 'ARRAY';
next if $$menuitem[4] ne 'always'
&& ($$menuitem[4] ne 'author' && $$menuitem[4] ne 'cca')
&& !$env{'request.course.id'};
next if $$menuitem[4] =~ /^mdc/
&& !$canedit;
next if $$menuitem[4] eq 'mdcCourse'
&& ($crstype eq 'Community');
next if $$menuitem[4] eq 'mdcCommunity'
&& ($crstype eq 'Course');
next if $$menuitem[4] eq 'nvgr'
&& $canvgr;
next if $$menuitem[4] eq 'vgr'
&& !$canvgr;
next if $$menuitem[4] eq 'cst'
&& !$canmodifyuser;
next if $$menuitem[4] eq 'ncst'
&& ($canmodifyuser || !$canviewroster);
next if $$menuitem[4] eq 'mgr'
&& !$canmgr;
next if $$menuitem[4] eq 'showresv'
&& !$showresv;
next if $$menuitem[4] eq 'whn'
&& !$canviewwnew;
next if $$menuitem[4] eq 'opa'
&& !$canmodpara;
next if $$menuitem[4] eq 'nvcg'
&& ($canviewgrps || !%groups);
next if $$menuitem[4] eq 'showsyllabus'
&& !$showsyllabus;
next if $$menuitem[4] eq 'showfeeds'
&& !$showfeeds;
next if $$menuitem[4] eq 'author'
&& !$author;
next if $$menuitem[4] eq 'cca'
&& !$canmodifycoauthor;
my $title = $menuitem->[3];
if (defined($secondary_submenu{$title})) {
my ($link,$target);
if ($menuitem->[0] ne '') {
$link = $menuitem->[0];
$target = '_top';
} else {
$link = '#';
}
my @scndsub;
if (ref($secondary_submenu{$title}) eq 'ARRAY') {
foreach my $item (@{$secondary_submenu{$title}}) {
if (ref($item) eq 'ARRAY') {
next if ($item->[2] eq 'vgr' && !$canvgr);
next if ($item->[2] eq 'opa' && !$canmodpara);
next if ($item->[2] eq 'cst' && !$canmodifyuser);
next if ($item->[2] eq 'mgr' && !$canmgr);
next if ($item->[2] eq 'vcg' && !$canviewgrps);
next if ($item->[2] eq 'mdc' && !$canedit);
push(@scndsub,$item);
}
}
if (@scndsub > 0) {
$menu .= &create_submenu($link,$target,$title,\@scndsub,1);
} elsif ($link ne '#') {
$menu .= '