--- loncom/interface/lonmenu.pm 2022/05/24 16:23:03 1.516 +++ loncom/interface/lonmenu.pm 2025/03/25 01:02:59 1.562 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Routines to control the menu # -# $Id: lonmenu.pm,v 1.516 2022/05/24 16:23:03 raeburn Exp $ +# $Id: lonmenu.pm,v 1.562 2025/03/25 01:02:59 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -99,7 +99,7 @@ It gets filled in the BEGIN block of thi =over -=item prep_menuitems(\@menuitem,$ltitarget,$deeplinktarget,$listclass,$linkattr) +=item prep_menuitems(\@menuitem,$target,$listclass,$linkattr) This routine wraps a menuitem in proper HTML. It is used by primary_menu() and secondary_menu(). @@ -210,7 +210,6 @@ use Apache::lonenc(); use Apache::lonlocal; use Apache::lonmsg(); use LONCAPA qw(:DEFAULT :match); -use LONCAPA::ltiutils; use HTML::Entities(); use Apache::lonwishlist(); @@ -220,9 +219,9 @@ use vars qw(@desklines %category_names % my @inlineremote; sub prep_menuitem { - my ($menuitem,$ltitarget,$deeplinktarget,$listclass,$linkattr) = @_; + my ($menuitem,$target,$listclass,$linkattr) = @_; return '' unless(ref($menuitem) eq 'ARRAY'); - my $link; + my ($link,$targetattr); if ($$menuitem[1]) { # graphical Link $link = "':'
  • ').'$link
  • |; + . qq| href="$$menuitem[0]"$targetattr $linkattr>$link|; } # primary_menu() evaluates @primary_menu and returns a two item array, @@ -249,7 +245,7 @@ sub prep_menuitem { # @primary_menu is filled within the BEGIN block of this module with # entries from mydesk.tab sub primary_menu { - my ($crstype,$ltimenu,$menucoll,$menuref,$links_disabled) = @_; + my ($crstype,$ltimenu,$menucoll,$menuref,$links_disabled,$links_target,$collapsible) = @_; my (%menu,%ltiexc,%menuopts); # each element of @primary contains following array: # (link url, icon path, alt text, link text, condition, position) @@ -267,10 +263,9 @@ sub primary_menu { my %roles_in_env; $rolecount = &Apache::lonroles::roles_from_env(\%roles_in_env,$update); } - my ($lti,$ltitarget,$deeplinktarget); + my $lti; if ($env{'request.lti.login'}) { $lti = 1; - $ltitarget = $env{'request.lti.target'}; if (ref($ltimenu) eq 'HASH') { foreach my $item ('fullname','logout') { unless ($ltimenu->{$item}) { @@ -279,8 +274,26 @@ sub primary_menu { } } } - if ($env{'request.deeplink.login'}) { - $deeplinktarget = $env{'request.deeplink.target'}; + my ($listclass,$linkattr,$target); + if ($links_disabled) { + $listclass = 'LCisDisabled'; + $linkattr = 'aria-disabled="true"'; + } + if ($links_target ne '') { + $target = $links_target; + } else { + my ($ltitarget,$deeplinktarget); + if ($env{'request.lti.login'}) { + $ltitarget = $env{'request.lti.target'}; + } + if ($env{'request.deeplink.login'}) { + $deeplinktarget = $env{'request.deeplink.target'}; + } + if (($ltitarget eq 'iframe') || ($deeplinktarget eq '_self')) { + $target = '_self'; + } else { + $target = '_top'; + } } if (($menucoll) && (ref($menuref) eq 'HASH')) { %menuopts = %{$menuref}; @@ -337,18 +350,10 @@ sub primary_menu { } } } - my ($listclass,$linkattr); - if ($links_disabled) { - $listclass = 'LCisDisabled'; - $linkattr = 'aria-disabled="true"'; - } if (defined($primary_submenu{$title})) { - my ($link,$target); + my $link; if ($menuitem->[0] ne '') { $link = $menuitem->[0]; - unless (($ltitarget eq 'iframe') || ($deeplinktarget eq '_self')) { - $target = '_top'; - } } else { $link = '#'; } @@ -361,6 +366,19 @@ sub primary_menu { ($item->[2] eq 'blog')) && (!&Apache::lonnet::usertools_access('','',$item->[2], undef,'tools'))); + if (($item->[2] eq 'browsepub') && ($item->[0] eq '/res/')) { + if ($env{'request.role'} =~ /^au\./) { + $item->[0] .= $env{'request.role.domain'}.'/?launch=1'; + } elsif ($env{'request.role'} =~ m{^ca\./($match_domain)/($match_username)$}) { + $item->[0] .= $1.'/'.$2.'/?launch=1'; + } elsif (&Apache::lonnet::allowed('bre',$env{'user.domain'})) { + $item->[0] .= $env{'user.domain'}.'/?launch=1'; + } elsif (&Apache::lonnet::allowed('bro','/res/')) { + $item->[0] .= '?launch=1'; + } else { + next; + } + } if ($env{'request.course.id'} && $menucoll) { next if ($item->[3]) && (!$menuopts{$item->[3]}); } @@ -396,7 +414,7 @@ sub primary_menu { 'helpdeskmail', $defdom,$origmail); if ($to ne '') { - $menu{$position} .= &prep_menuitem($menuitem,$ltitarget,$deeplinktarget,$listclass,$linkattr); + $menu{$position} .= &prep_menuitem($menuitem,$target,$listclass,$linkattr); } } else { $menu{$position} .= ($listclass?'
  • ':'
  • '). @@ -409,13 +427,17 @@ sub primary_menu { $$menuitem[0] = '/adm/login'; } } - $menu{$position} .= prep_menuitem($menuitem,$ltitarget,$deeplinktarget,$listclass,$linkattr); + $menu{$position} .= prep_menuitem($menuitem,$target,$listclass,$linkattr); } else { - $menu{$position} .= prep_menuitem($menuitem,$ltitarget,$deeplinktarget,$listclass,$linkattr); + $menu{$position} .= prep_menuitem($menuitem,$target,$listclass,$linkattr); } } my @output = ('',''); if ($menu{'left'} ne '') { + if ($collapsible) { + $menu{'left'} = ($listclass?'
  • ':'
  • '). + ' 
  • '.$menu{'left'}; + } $output[0] = "
      $menu{'left'}
    "; } if ($menu{'right'} ne '') { @@ -431,10 +453,10 @@ sub primary_menu { # #TODO this should probably be moved somewhere more central #since it can be used by different parts of the system -sub getauthor{ +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? + #co- or assistant 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 @@ -450,7 +472,8 @@ sub getauthor{ } sub secondary_menu { - my ($httphost,$ltiscope,$ltimenu,$noprimary,$menucoll,$menuref,$links_disabled) = @_; + my ($httphost,$ltiscope,$ltimenu,$noprimary,$menucoll,$menuref, + $links_disabled,$links_target) = @_; my $menu; my $crstype = &Apache::loncommon::course_type(); @@ -474,6 +497,15 @@ sub secondary_menu { my $canplc = &Apache::lonnet::allowed('plc', $crs_sec); my $author = &getauthor(); + my ($is_author,$is_coauthor); + if ($author) { + if ($env{'request.role'} =~ /^au\./) { + $is_author = 1; + } elsif ($env{'request.role'} =~ /^ca\./) { + $is_coauthor = 1; + } + } + my ($cdom,$cnum,$showsyllabus,$showfeeds,$showresv,$grouptools, $lti,$ltimapres,%ltiexc,%menuopts); $grouptools = 0; @@ -527,38 +559,66 @@ sub secondary_menu { %menuopts = %{$menuref}; } - my ($listclass,$linkattr); + my ($listclass,$linkattr,$target); if ($links_disabled) { $listclass = 'LCisDisabled'; $linkattr = 'aria-disabled="true"'; } - my ($canmodifycoauthor); + my ($canlistcoauthors,$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; } + } elsif ($env{'request.role'} =~ m{^(aa|ca)\./($match_domain/$match_username)$}) { + my ($role,$extent) = ($1,$2); + if (&Apache::lonnet::allowed('vca',$extent)) { + if ($env{"environment.internal.manager./$extent"}) { + $canmodifycoauthor = 1; + } else { + $canlistcoauthors = 1; + } + } elsif (&Apache::lonnet::allowed('vaa',$extent)) { + $canlistcoauthors = 1; + } } - - my ($roleswitcher_js,$roleswitcher_form,$ltitarget,$deeplinktarget); - if ($env{'request.lti.login'}) { - $ltitarget = $env{'request.lti.target'}; - } - if ($env{'request.deeplink.login'}) { - $deeplinktarget = $env{'request.deeplink.target'}; + my ($roleswitcher_js,$roleswitcher_form); + if ($links_target ne '') { + $target = $links_target; + } else { + my ($ltitarget,$deeplinktarget); + if ($env{'request.lti.login'}) { + $ltitarget = $env{'request.lti.target'}; + } + if ($env{'request.deeplink.login'}) { + $deeplinktarget = $env{'request.deeplink.target'}; + } + if (($ltitarget eq 'iframe') || ($deeplinktarget eq '_self')) { + $target = '_self'; + } else { + $target = '_top'; + } } foreach my $menuitem (@secondary_menu) { # evaluate conditions next if ref($menuitem) ne 'ARRAY'; next if (($crstype eq 'Placement') && ($$menuitem[3] ne 'Roles') && (!$env{'request.role.adv'})); - next if $$menuitem[4] ne 'always' - && ($$menuitem[4] ne 'author' && $$menuitem[4] ne 'cca') + next if $$menuitem[4] ne 'always' + && $$menuitem[4] ne 'coauthor' + && $$menuitem[4] ne 'author' + && $$menuitem[4] ne 'authorspace' + && $$menuitem[4] ne 'vca' + && $$menuitem[4] ne 'mca' && !$env{'request.course.id'}; next if $$menuitem[4] =~ /^crsedit/ && (!$canedit && !$canvieweditor); + next if $$menuitem[4] eq 'crseditCourse' + && ($crstype eq 'Community'); + next if $$menuitem[4] eq 'crseditCommunity' + && ($crstype ne 'Community'); next if $$menuitem[4] eq 'nvgr' && ($canvgr || $ltiexc{'grades'}); next if $$menuitem[4] eq 'vgr' @@ -583,9 +643,17 @@ sub secondary_menu { && !$showfeeds; next if $$menuitem[4] eq 'plc' && !$canplc; - next if $$menuitem[4] eq 'author' + next if $$menuitem[4] eq 'authorspace' && !$author; - next if $$menuitem[4] eq 'cca' + next if $$menuitem[4] eq 'author' + && !$is_author; + next if $$menuitem[4] eq 'coauthor' + && !$is_coauthor; + next if $$menuitem[4] eq 'vca' + && (!$canlistcoauthors || $canmodifycoauthor); + next if $$menuitem[4] eq 'vaa' + && (!$canlistcoauthors || $canmodifycoauthor); + next if $$menuitem[4] eq 'mca' && !$canmodifycoauthor; next if $$menuitem[4] eq 'notltimapres' && $ltimapres; @@ -603,12 +671,9 @@ sub secondary_menu { } } if (defined($secondary_submenu{$title})) { - my ($link,$target); + my $link; if ($menuitem->[0] ne '') { $link = $menuitem->[0]; - unless (($ltitarget eq 'iframe') || ($deeplinktarget eq '_self')) { - $target = '_top'; - } } else { $link = '#'; } @@ -624,8 +689,8 @@ sub secondary_menu { next if ($item->[2] eq 'vcg' && !$canviewgrps); next if ($item->[2] eq 'crsedit' && !$canedit && !$canvieweditor); next if ($item->[2] eq 'params' && !$canmodpara && !$canviewpara); - next if ($item->[2] eq 'author' && !$author); - next if ($item->[2] eq 'cca' && !$canmodifycoauthor); + next if ($item->[2] eq 'author' && !$is_author); + next if ($item->[2] eq 'vca' && !$canlistcoauthors); next if ($item->[2] eq 'lti' && !$lti); if ($item->[2] =~ /^lti(portfolio|wishlist|blog)$/) { my $tool = $1; @@ -657,7 +722,7 @@ sub secondary_menu { &roles_selector( $env{'course.' . $env{'request.course.id'} . '.domain'}, $env{'course.' . $env{'request.course.id'} . '.num'}, - $httphost + $httphost,$target,$menucoll,$menuref ); if (($$menuitem[5]) && (!$menuopts{$$menuitem[5]})) { next unless ($has_opa_priv); @@ -691,7 +756,7 @@ sub secondary_menu { } $$menuitem[0] = &HTML::Entities::encode($$menuitem[0],'&<>"'); } - $menu .= &prep_menuitem(\@$menuitem,$ltitarget,$deeplinktarget,$listclass,$linkattr); + $menu .= &prep_menuitem(\@$menuitem,$target,$listclass,$linkattr); } } if ($menu =~ /\[url\].*\[symb\]/) { @@ -711,6 +776,20 @@ sub secondary_menu { } $menu =~ s/\[url\]/$escurl/g; $menu =~ s/\[symb\]/$escsymb/g; + } elsif (($menu =~ m{/adm/preferences\?}) && ($menu =~ /\[returnurl\]/)) { + my $returnurl = $ENV{'REQUEST_URI'}; + if ($ENV{'REQUEST_URI'} =~ m{/adm/preferences\?action=authorsettings\&returnurl=([^\&]+)$}) { + $returnurl = $1; + } + if (($returnurl =~ m{^/adm/createuser($|\?action=)}) || + ($returnurl =~ m{^/priv/$match_domain/$match_username}) || + ($returnurl =~ m{^/res(/?$|/$match_domain/$match_username)})) { + $returnurl =~ s{\?.*$}{}; + $returnurl = '&returnurl='.&HTML::Entities::encode($returnurl,'"<>&\''); + } else { + undef($returnurl); + } + $menu =~ s/\[returnurl\]/$returnurl/; } $menu =~ s/\[uname\]/$$author{user}/g; $menu =~ s/\[udom\]/$$author{dom}/g; @@ -731,14 +810,14 @@ sub secondary_menu { sub create_submenu { my ($link,$target,$title,$submenu,$translate,$addclass,$listclass,$linkattr) = @_; return unless (ref($submenu) eq 'ARRAY'); - my $disptarget; - if ($target ne '') { - $disptarget = ' target="'.$target.'"'; + my $targetattr; + if (($target ne '') && ($link ne '#')) { + $targetattr = ' target="'.$target.'"'; } my $menu = '
  • '. - ''. + ''. ''.$title. - ''. + ''. ' ▼'. '