--- loncom/interface/lonnavmaps.pm 2017/12/21 03:50:57 1.538 +++ loncom/interface/lonnavmaps.pm 2018/12/29 23:24:40 1.545 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Navigate Maps Handler # -# $Id: lonnavmaps.pm,v 1.538 2017/12/21 03:50:57 raeburn Exp $ +# $Id: lonnavmaps.pm,v 1.545 2018/12/29 23:24:40 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -71,7 +71,7 @@ processed. Apache::lonnavmaps provides an object model for manipulating this information in a higher-level fashion than directly manipulating -the hash. It also provides access to several auxilary functions +the hash. It also provides access to several auxiliary functions that aren't necessarily stored in the Big Hash, but are a per- resource sort of value, like whether there is any feedback on a given resource. @@ -92,7 +92,7 @@ graded for named user(s) or specific COD domain, or CODE can be passed as arguments when creating a new navmap object. -Note if you want things like "due dates for another student, +Note if you want things like "due dates for another student", you would use the EXT function instead of lonnavmaps. That said, the lonnavmaps module can still help, because many things, such as the course structure, are usually constant @@ -702,7 +702,17 @@ sub getDescription { } if (($status == $res->ANSWER_OPEN || $status == $res->PARTIALLY_CORRECT) && $res->handgrade($part) ne 'yes') { - return &Apache::lonhtmlcommon::direct_parm_link(&mt("Answer available"),$res->symb(),'answerdate,duedate',$part); + my $msg = &mt('Answer available'); + my $parmlist = 'answerdate,duedate'; + if (($res->is_tool) && ($res->is_gradable())) { + if (($status == $res->PARTIALLY_CORRECT) && ($res->parmval('retrypartial',$part))) { + $msg = &mt('Grade received'); + $parmlist = 'retrypartial'; + } else { + $msg = &mt('Grade available'); + } + } + return &Apache::lonhtmlcommon::direct_parm_link($msg,$res->symb(),$parmlist,$part); } if ($status == $res->EXCUSED) { return &mt("Excused by instructor"); @@ -953,11 +963,32 @@ sub render_resource { $newBranchText = ".mt('Branch')."; } - # links to open and close the folder - my $whitespace = $location.'/whitespace_21.gif'; - my $linkopen = "".""; - my $linkclose = ""; + my ($nomodal,$linkopen,$linkclose); + unless ($resource->is_map() || $params->{'resource_nolink'}) { + $linkopen = ""; + $linkclose = ""; + if (($params->{'modalLink'}) && (!$resource->is_sequence())) { + if ($link =~m{^(?:|/adm/wrapper)/ext/([^#]+)}) { + my $exturl = $1; + if (($ENV{'SERVER_PORT'} == 443) && ($exturl !~ /^https:/)) { + $nomodal = 1; + } + } elsif (($link eq "/public/$LONCAPA::match_domain/$LONCAPA::match_courseid/syllabus") && + ($env{'request.course.id'}) && ($ENV{'SERVER_PORT'} == 443) && + ($env{'course.'.$env{'request.course.id'}.'.externalsyllabus'} =~ m{^http://})) { + $nomodal = 1; + } + my $esclink = &js_escape($link); + if ($nomodal) { + $linkopen .= ""; + } else { + $linkopen .= ""; + } + } else { + $linkopen .= ""; + } + } # Default icon: unknown page my $icon = ""; @@ -1005,13 +1036,14 @@ sub render_resource { '&jump=' . &escape($resource->symb()) . "&folderManip=1\">"; - + $linkclose = ''; } else { # Don't allow users to manipulate folder $icon = "navmap.$folderType." . ($nowOpen ? 'closed' : 'open') . '.gif'; $icon = ""."\"".($nowOpen"; if ($params->{'caller'} eq 'sequence') { $linkopen = ""; + $linkclose = ''; } else { $linkopen = ""; $linkclose = ""; @@ -1030,10 +1062,15 @@ sub render_resource { } if ($params->{'mapHidden'} || $resource->randomout()) { $nonLinkedText .= ' ('.&mt('hidden').') '; + } elsif ($params->{'mapUnlisted'}) { + $nonLinkedText .= ' ('.&mt('unlisted').') '; } } else { if ($resource->randomout()) { $nonLinkedText .= ' ('.&mt('hidden').') '; + } elsif (($resource->deeplink($params->{caller}) eq 'absent') || + ($resource->deeplink($params->{caller}) eq 'grades')) { + $nonLinkedText .= ' ('.&mt('unlisted').') '; } } if (!$resource->condval()) { @@ -1084,10 +1121,19 @@ sub render_resource { } if (!$params->{'resource_nolink'} && !$resource->is_sequence() && !$resource->is_empty_sequence) { - $result .= "$curMarkerBegin$title$partLabel$curMarkerEnd$editmapLink$nonLinkedText"; - } else { - $result .= "$curMarkerBegin$linkopen$title$partLabel$curMarkerEnd$editmapLink$nonLinkedText"; + $linkclose = ''; + if ($params->{'modalLink'}) { + my $esclink = &js_escape($link); + if ($nomodal) { + $linkopen = ""; + } else { + $linkopen = ""; + } + } else { + $linkopen = ""; + } } + $result .= "$curMarkerBegin$linkopen$title$partLabel$linkclose$curMarkerEnd$editmapLink$nonLinkedText"; return $result; } @@ -1348,7 +1394,9 @@ sub render { # Without renaming the filterfunc, the server seems to go into # an infinite loop my $oldFilterFunc = $filterFunc; - $filterFunc = sub { my $res = shift; return !$res->randomout() && + $filterFunc = sub { my $res = shift; return !$res->randomout() && + ($res->deeplink($args->{'caller'}) ne 'absent') && + ($res->deeplink($args->{'caller'}) ne 'grades') && &$oldFilterFunc($res);}; } @@ -1725,6 +1773,11 @@ END $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; } + my $inhibitmenu; + if ($args->{'modalLink'}) { + $inhibitmenu = '&inhibitmenu=yes'; + } + while (1) { if ($args->{'sort'}) { $curRes = shift(@resources); @@ -1760,6 +1813,7 @@ END # If this is an empty sequence and we're filtering them, continue on $args->{'mapHidden'} = 0; + $args->{'mapUnlisted'} = 0; if (($curRes->is_map()) && (!$curRes->{DATA}->{HAS_VISIBLE_CHILDREN})) { if ($args->{'suppressEmptySequences'}) { next; @@ -1772,6 +1826,15 @@ END } else { next; } + } else { + my $deeplink = $navmap->get_mapparam(undef,$mapname,"0.deeplink"); + if (($deeplink eq 'absent') || ($deeplink eq 'grades')) { + if ($userCanSeeHidden) { + $args->{'mapUnlisted'} = 1; + } else { + next; + } + } } } } @@ -1834,8 +1897,17 @@ END $args->{'condensed'} = 1; } } - } - + } + # If deep-link parameter is set (and is not set to full) suppress link + # unless priviliged user, or calling context is sequence, and parameter + # set at map level + if ((!$curRes->deeplink($args->{'caller'})) || + ($curRes->deeplink($args->{'caller'}) eq 'full') || &advancedUser()) { + $args->{'resource_nolink'} = 0; + } else { + $args->{'resource_nolink'} = 1; + } + # If the multipart problem was condensed, "forget" it was multipart if (scalar(@parts) == 1) { $args->{'multipart'} = 0; @@ -1861,14 +1933,20 @@ END if ($env{'request.course.id'}) { if (($is_ssl) && ($src =~ m{^\Q/public/$cdom/$cnum/syllabus\E($|\?)}) && ($env{'course.'.$env{'request.course.id'}.'.externalsyllabus'} =~ m{^http://})) { - if ($hostname ne '') { - $src = 'http://'.$hostname.$src; + unless (&Apache::lonnet::uses_sts()) { + if ($hostname ne '') { + $src = 'http://'.$hostname.$src; + } + $src .= ($srcHasQuestion? '&' : '?') . 'usehttp=1'; + $srcHasQuestion = 1; } - $src .= ($srcHasQuestion? '&' : '?') . 'usehttp=1'; - $srcHasQuestion = 1; } elsif (($is_ssl) && ($src =~ m{^\Q/adm/wrapper/ext/\E(?!https:)})) { - if ($hostname ne '') { - $src = 'http://'.$hostname.$src; + unless (&Apache::lonnet::uses_sts()) { + if ($hostname ne '') { + $src = 'http://'.$hostname.$src; + } + $src .= ($srcHasQuestion? '&' : '?') . 'usehttp=1'; + $srcHasQuestion = 1; } } } @@ -1878,7 +1956,7 @@ END } else { $args->{"resourceLink"} = $src. ($srcHasQuestion?'&':'?') . - 'symb=' . &escape($symb).$anchor; + 'symb=' . &escape($symb).$inhibitmenu.$anchor; } } # Now, we've decided what parts to show. Loop through them and @@ -2913,7 +2991,7 @@ sub recursed_crumbs { my $pc = $map->map_pc(); next if ((!$pc) || ($pc == 1)); push(@links,$map); - push(@revmapinfo,{'href' => $map->link().'?navmap=1','text' => $map->title(),'no_mt' => 1,}); + push(@revmapinfo,{'href' => $env{'request.use_absolute'}.$map->link().'?navmap=1','text' => $map->title(),'no_mt' => 1,}); $totallength += length($map->title()); } my $numlinks = scalar(@links); @@ -2928,7 +3006,7 @@ sub recursed_crumbs { foreach my $map (@links) { my $showntitle = &truncate_crumb_text($map->title(),$avg); if ($showntitle ne '') { - push(@revmapinfo,{'href' => $map->link().'?navmap=1','text' => $showntitle,'no_mt' => 1,}); + push(@revmapinfo,{'href' => $env{'request.use_absolute'}.$map->link().'?navmap=1','text' => $showntitle,'no_mt' => 1,}); } } } @@ -3436,6 +3514,71 @@ sub usedVersion { return $self->navhash("version_$linkurl"); } +sub isFirstResource { + my $self = shift; + my $map = shift; + my $symb = shift; + return unless (ref($map)); + my $isfirst; + my $firstResource = $map->map_start(); + if (ref($firstResource)) { + if ((!$firstResource->is_map()) && ($firstResource->src() ne '')) { + if ($firstResource->symb() eq $symb) { + $isfirst = 1; + } else { + $isfirst = 0; + } + } else { + my $it = $self->getIterator($firstResource,undef,undef,1); + while ( my $res=$it->next()) { + if ((ref($res)) && ($res->src() ne '') && (!$res->is_map())) { + if ($res->symb() eq $symb) { + $isfirst = 1; + } else { + $isfirst = 0; + } + last; + } + } + } + } + return $isfirst; +} + +sub isLastResource { + my $self = shift; + my $map = shift; + my $symb = shift; + return unless (ref($map)); + my $islast; + my $lastResource = $map->map_finish(); + if (ref($lastResource)) { + if ((!$lastResource->is_map()) && ($lastResource->src() ne '')) { + if ($lastResource->symb() eq $symb) { + $islast = 1; + } else { + $islast = 0; + } + } else { + my $currRes = $self->getBySymb($symb); + if (ref($currRes)) { + my $it = $self->getIterator($currRes,undef,undef,1); + while ( my $res=$it->next()) { + if ((ref($res)) && ($res->src() ne '') && (!$res->is_map())) { + if ($res->symb() eq $symb) { + $islast = 1; + } else { + $islast = 0; + } + last; + } + } + } + } + } + return $islast; +} + 1; package Apache::lonnavmaps::iterator; @@ -4582,7 +4725,6 @@ sub is_task { sub is_empty_sequence { my $self=shift; - my $src = $self->src(); return !$self->is_page() && $self->navHash("is_map_", 1) && !$self->navHash("map_type_" . $self->map_pc()); } @@ -5002,6 +5144,17 @@ sub slot_control { my $available = $self->parmval("available", $part); return ($useslots,$availablestudent,$available); } +sub deeplink { + my ($self,$caller) = @_; + if ($caller eq 'sequence') { + my @deeplink = $self->parmval("deeplink"); + if ($deeplink[1] eq 'resource') { + return $deeplink[0]; + } + } else { + return $self->parmval("deeplink"); + } +} # Multiple things need this sub getReturnHash {