--- loncom/interface/lonnavmaps.pm 2004/11/10 22:20:50 1.303 +++ loncom/interface/lonnavmaps.pm 2005/04/11 12:20:22 1.321 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Navigate Maps Handler # -# $Id: lonnavmaps.pm,v 1.303 2004/11/10 22:20:50 albertel Exp $ +# $Id: lonnavmaps.pm,v 1.321 2005/04/11 12:20:22 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -30,12 +30,16 @@ package Apache::lonnavmaps; use strict; +use GDBM_File; use Apache::Constants qw(:common :http); use Apache::loncommon(); use Apache::lonmenu(); +use Apache::lonenc(); use Apache::lonlocal; +use Apache::lonnet; use POSIX qw (floor strftime); use Data::Dumper; # for debugging, not always +use Time::HiRes qw( gettimeofday tv_interval ); # symbolic constants sub SYMB { return 1; } @@ -106,7 +110,7 @@ sub launch_win { } sub close { - if ($ENV{'environment.remotenavmap'} ne 'on') { return ''; } + if ($env{'environment.remotenavmap'} ne 'on') { return ''; } return(< window.status='Accessing Nav Control'; @@ -120,8 +124,8 @@ ENDCLOSE } sub update { - if ($ENV{'environment.remotenavmap'} ne 'on') { return ''; } - if (!$ENV{'request.course.id'}) { return ''; } + if ($env{'environment.remotenavmap'} ne 'on') { return ''; } + if (!$env{'request.course.id'}) { return ''; } if ($ENV{'REQUEST_URI'}=~m|^/adm/navmaps|) { return ''; } return(< @@ -140,10 +144,10 @@ sub handler { sub real_handler { my $r = shift; - + #my $t0=[&gettimeofday()]; # Handle header-only request if ($r->header_only) { - if ($ENV{'browser.mathml'}) { + if ($env{'browser.mathml'}) { &Apache::loncommon::content_type($r,'text/xml'); } else { &Apache::loncommon::content_type($r,'text/html'); @@ -153,7 +157,7 @@ sub real_handler { } # Send header, don't cache this page - if ($ENV{'browser.mathml'}) { + if ($env{'browser.mathml'}) { &Apache::loncommon::content_type($r,'text/xml'); } else { &Apache::loncommon::content_type($r,'text/html'); @@ -162,7 +166,7 @@ sub real_handler { $r->send_http_header; my %toplinkitems=(); - + &add_linkitem(\%toplinkitems,'blank','',"Select Action"); if ($ENV{QUERY_STRING} eq 'collapseExternal') { &Apache::lonnet::put('environment',{'remotenavmap' => 'off'}); &Apache::lonnet::appenv('environment.remotenavmap' => 'off'); @@ -182,8 +186,9 @@ MENU $navstatus MENU } + my $html=&Apache::lonxml::xmlbegin(); $r->print(<<"ENDSUBM"); - + $html '); $r->rflush(); @@ -275,9 +280,9 @@ ENDSUBM if ($sequenceCount == 1) { # The automatic iterator creation in the render call # will pick this up. We know the condition because - # the defined($ENV{'form.filter'}) also ensures this + # the defined($env{'form.filter'}) also ensures this # is a fresh call. - $ENV{'form.filter'} = "$sequenceId"; + $env{'form.filter'} = "$sequenceId"; } } @@ -292,10 +297,10 @@ ENDSUBM '); } - if ($ENV{'environment.remotenavmap'} ne 'on') { + if ($env{'environment.remotenavmap'} ne 'on') { $r->print(&launch_win('link','yes',\%toplinkitems)); } - if ($ENV{'environment.remotenavmap'} eq 'on') { + if ($env{'environment.remotenavmap'} eq 'on') { &add_linkitem(\%toplinkitems,'closenav','collapse()', "Close navigation window"); } @@ -322,10 +327,10 @@ ENDSUBM pop @$stack; # last resource in the stack is the problem # itself, which we don't need in the map stack my @mapPcs = map {$_->map_pc()} @$stack; - $ENV{'form.filter'} = join(',', @mapPcs); + $env{'form.filter'} = join(',', @mapPcs); # Mark as both "here" and "jump" - $ENV{'form.postsymb'} = $curRes->symb(); + $env{'form.postsymb'} = $curRes->symb(); } } } @@ -346,42 +351,42 @@ ENDSUBM # Display only due homework. my $showOnlyHomework = 0; - if ($ENV{'form.showOnlyHomework'} eq "1") { + if ($env{'form.showOnlyHomework'} eq "1") { $showOnlyHomework = 1; $suppressEmptySequences = 1; $filterFunc = sub { my $res = shift; return $res->completable() || $res->is_map(); }; &add_linkitem(\%toplinkitems,'everything', - 'location.href="navmaps?sort='.$ENV{'form.sort'}.'"', + 'location.href="navmaps?sort='.$env{'form.sort'}.'"', "Show Everything"); $r->print("

".&mt("Uncompleted Homework")."

"); - $ENV{'form.filter'} = ''; - $ENV{'form.condition'} = 1; + $env{'form.filter'} = ''; + $env{'form.condition'} = 1; $resource_no_folder_link = 1; } else { &add_linkitem(\%toplinkitems,'uncompleted', - 'location.href="navmaps?sort='.$ENV{'form.sort'}. + 'location.href="navmaps?sort='.$env{'form.sort'}. '&showOnlyHomework=1"', "Show Only Uncompleted Homework"); } - my %selected=($ENV{'form.sort'} => 'selected=on'); + my %selected=($env{'form.sort'} => 'selected=on'); my $sort_html=("
- +
"); # renderer call my $renderArgs = { 'cols' => [0,1,2,3], - 'sort' => $ENV{'form.sort'}, + 'sort' => $env{'form.sort'}, 'url' => '/adm/navmaps', 'navmap' => $navmap, 'suppressNavmap' => 1, @@ -403,6 +408,8 @@ ENDSUBM $r->print("

This course is empty.

"); } } + #my $td=&tv_interval($t0); + #$r->print("
$td"); $r->print(""); $r->rflush(); @@ -433,7 +440,6 @@ sub removeFromFilter { # Convenience function: Given a stack returned from getStack on the iterator, # return the correct src() value. -# Later, this should add an anchor when we start putting anchors in pages. sub getLinkForResource { my $stack = shift; my $res; @@ -441,14 +447,18 @@ sub getLinkForResource { # Check to see if there are any pages in the stack foreach $res (@$stack) { if (defined($res)) { + my $anchor; if ($res->is_page()) { - return $res->link(); + foreach (@$stack) { if (defined($_)) { $anchor = $_; } } + $anchor=&Apache::lonnet::escape($anchor->shown_symb()); + return ($res->link(),$res->shown_symb(),$anchor); } # in case folder was skipped over as "only sequence" my ($map,$id,$src)=&Apache::lonnet::decode_symb($res->symb()); if ($map=~/\.page$/) { - return &Apache::lonnet::clutter($map).'#'. - &Apache::lonnet::escape(&Apache::lonnet::declutter($src)); + my $url=&Apache::lonnet::clutter($map); + $anchor=&Apache::lonnet::escape($src->shown_symb()); + return ($url,$res->shown_symb(),$anchor); } } } @@ -461,7 +471,7 @@ sub getLinkForResource { if (defined($_)) { $res = $_; } } - return $res->link(); + return ($res->link(),$res->shown_symb()); } # Convenience function: This separates the logic of how to create @@ -555,10 +565,10 @@ sub lastTry { $res->duedate($part) > time(); } -# This puts a human-readable name on the ENV variable. +# This puts a human-readable name on the env variable. sub advancedUser { - return $ENV{'request.role.adv'}; + return $env{'request.role.adv'}; } @@ -861,13 +871,13 @@ automatically. =over 4 -=item * B: default: constructs one from %ENV +=item * B: default: constructs one from %env A reference to a fresh ::iterator to use from the navmaps. The rendering will reflect the options passed to the iterator, so you can use that to just render a certain part of the course, if you like. If one is not passed, the renderer will attempt to construct one from -ENV{'form.filter'} and ENV{'form.condition'} information, plus the +env{'form.filter'} and env{'form.condition'} information, plus the 'iterator_map' parameter if any. =item * B: default: not used @@ -877,11 +887,11 @@ instruct the renderer to render only a p the source of the map you want to process, like '/res/103/jerf/navmap.course.sequence'. -=item * B: default: constructs one from %ENV +=item * B: default: constructs one from %env A reference to a navmap, used only if an iterator is not passed in. If this is necessary to make an iterator but it is not passed in, a new -one will be constructed based on ENV info. This is useful to do basic +one will be constructed based on env info. This is useful to do basic error checking before passing it off to render. =item * B: default: must be passed in @@ -907,12 +917,12 @@ then only one line will be displayed for all parts will always be displayed. If showParts is 0, this is ignored. -=item * B: default: determined from %ENV +=item * B: default: determined from %env A string identifying the URL to place the anchor 'curloc' at. It is the responsibility of the renderer user to ensure that the #curloc is in the URL. By default, determined through -the use of the ENV{} 'jump' information, and should normally "just +the use of the env{} 'jump' information, and should normally "just work" correctly. =item * B: default: empty string @@ -940,7 +950,7 @@ are allowing the user to open and close Describes the currently-open row number to cause the browser to jump to, because the user just opened that folder. By default, pulled from -the Jump information in the ENV{'form.*'}. +the Jump information in the env{'form.*'}. =item * B: default: false @@ -1009,6 +1019,15 @@ sub render_resource { my $nonLinkedText = ''; # stuff after resource title not in link my $link = $params->{"resourceLink"}; + + # The URL part is not escaped at this point, but the symb is... + # The stuff to the left of the ? must have ' replaced by \' since + # it will be quoted with ' in the href. + + my ($left,$right) = split(/\?/, $link); + $left =~ s/'/\\'/g; + $link = $left.'?'.$right; + my $src = $resource->src(); my $it = $params->{"iterator"}; my $filter = $it->{FILTER}; @@ -1024,7 +1043,11 @@ sub render_resource { } # links to open and close the folder + + my $linkopen = ""; + + my $linkclose = ""; # Default icon: unknown page @@ -1037,7 +1060,7 @@ sub render_resource { $icon = $params->{'indentString'}; } } else { - $icon = ""; + $icon = ""; } # Display the correct map icon to open or shut map @@ -1065,6 +1088,7 @@ sub render_resource { '&jump=' . &Apache::lonnet::escape($resource->symb()) . "&folderManip=1'>"; + } else { # Don't allow users to manipulate folder $icon = "navmap.$folderType." . ($nowOpen ? 'closed' : 'open') . @@ -1092,6 +1116,7 @@ sub render_resource { } # Decide what to display + $result .= "$newBranchText$linkopen$icon$linkclose"; my $curMarkerBegin = ''; @@ -1109,7 +1134,7 @@ sub render_resource { !$params->{'condensed'}) { my $displaypart=$resource->part_display($part); $partLabel = " (Part: $displaypart)"; - $link.='#'.&Apache::lonnet::escape($part); + if ($link!~/\#/) { $link.='#'.&Apache::lonnet::escape($part); } $title = ""; } @@ -1118,7 +1143,7 @@ sub render_resource { } my $target; - if ($ENV{'environment.remotenavmap'} eq 'on') { + if ($env{'environment.remotenavmap'} eq 'on') { $target=' target="loncapaclient" '; } if (!$params->{'resource_nolink'} && !$resource->is_sequence() && !$resource->is_empty_sequence) { @@ -1365,7 +1390,7 @@ sub render { # marker my $filterHash = {}; # Figure out what we're not displaying - foreach (split(/\,/, $ENV{"form.filter"})) { + foreach (split(/\,/, $env{"form.filter"})) { if ($_) { $filterHash->{$_} = "1"; } @@ -1385,11 +1410,11 @@ sub render { } my $condition = 0; - if ($ENV{'form.condition'}) { + if ($env{'form.condition'}) { $condition = 1; } - if (!$ENV{'form.folderManip'} && !defined($args->{'iterator'})) { + if (!$env{'form.folderManip'} && !defined($args->{'iterator'})) { # Step 1: Check to see if we have a navmap if (!defined($navmap)) { $navmap = Apache::lonnavmaps::navmap->new(); @@ -1399,16 +1424,24 @@ sub render { # Step two: Locate what kind of here marker is necessary # Determine where the "here" marker is and where the screen jumps to. - if ($ENV{'form.postsymb'}) { - $here = $jump = $ENV{'form.postsymb'}; - } elsif ($ENV{'form.postdata'}) { + if ($env{'form.postsymb'}) { + $here = $jump = &Apache::lonnet::symbclean($env{'form.postsymb'}); + } elsif ($env{'form.postdata'}) { # couldn't find a symb, is there a URL? - my $currenturl = $ENV{'form.postdata'}; + my $currenturl = $env{'form.postdata'}; #$currenturl=~s/^http\:\/\///; #$currenturl=~s/^[^\/]+//; $here = $jump = &Apache::lonnet::symbread($currenturl); - } + } else { + my $last; + if (tie(my %hash,'GDBM_File',$env{'request.course.fn'}.'_symb.db', + &GDBM_READER(),0640)) { + $last=$hash{'last_known'}; + untie(%hash); + } + if ($last) { $here = $jump = $last; } + } # Step three: Ensure the folders are open my $mapIterator = $navmap->getIterator(undef, undef, undef, 1); @@ -1435,16 +1468,16 @@ sub render { } } - if ( !defined($args->{'iterator'}) && $ENV{'form.folderManip'} ) { # we came from a user's manipulation of the nav page + if ( !defined($args->{'iterator'}) && $env{'form.folderManip'} ) { # we came from a user's manipulation of the nav page # If this is a click on a folder or something, we want to preserve the "here" # from the querystring, and get the new "jump" marker - $here = $ENV{'form.here'}; - $jump = $ENV{'form.jump'}; + $here = $env{'form.here'}; + $jump = $env{'form.jump'}; } my $it = $args->{'iterator'}; if (!defined($it)) { - # Construct a default iterator based on $ENV{'form.'} information + # Construct a default iterator based on $env{'form.'} information # Step 1: Check to see if we have a navmap if (!defined($navmap)) { @@ -1555,11 +1588,9 @@ END my @allres=$navmap->retrieveResources(); foreach my $resource (@allres) { if ($resource->hasDiscussion()) { - my $ressymb; - if ($resource->symb() =~ m-(___adm/\w+/\w+)/(\d+)/bulletinboard$-) { - $ressymb = 'bulletin___'.$2.$1.'/'.$2.'/bulletinboard'; - } else { - $ressymb = $resource->symb(); + my $ressymb = $resource->symb(); + if ($ressymb =~ m-___adm/\w+/\w+/\d+/bulletinboard$-) { + $ressymb = $resource->wrap_symb(); } $haveDisc .= $ressymb.':'; $totdisc ++; @@ -1579,14 +1610,14 @@ END if ($args->{'caller'} eq 'navmapsdisplay') { $result .= ''; - if ($ENV{'environment.remotenavmap'} ne 'on') { + if ($env{'environment.remotenavmap'} ne 'on') { $result .= ''; } else { $result .= ''; } $result.=&show_linkitems($args->{'linkitems'}); if ($args->{'sort_html'}) { - if ($ENV{'environment.remotenavmap'} ne 'on') { + if ($env{'environment.remotenavmap'} ne 'on') { $result.=''. ''; } else { @@ -1829,7 +1860,26 @@ END # Add part 0 so we display it correctly. unshift @parts, '0'; } - + + { + my ($src,$symb,$anchor,$stack); + if ($args->{'sort'}) { + my $it = $navmap->getIterator(undef, undef, undef, 1); + while ( my $res=$it->next()) { + if (ref($res) && + $res->symb() eq $curRes->symb()) { last; } + } + $stack=$it->getStack(); + } else { + $stack=$it->getStack(); + } + ($src,$symb,$anchor)=getLinkForResource($stack); + if (defined($anchor)) { $anchor='#'.$anchor; } + my $srcHasQuestion = $src =~ /\?/; + $args->{"resourceLink"} = $src. + ($srcHasQuestion?'&':'?') . + 'symb=' . &Apache::lonnet::escape($symb).$anchor; + } # Now, we've decided what parts to show. Loop through them and # show them. foreach my $part (@parts) { @@ -1840,22 +1890,6 @@ END # Set up some data about the parts that the cols might want my $filter = $it->{FILTER}; - my $src; - if ($args->{'sort'}) { - $src = $curRes->src(); # FIXME this is wrong for .pages - } else { - my $stack = $it->getStack(); - $src=getLinkForResource($stack); - } - my $anchor=''; - if ($src=~s/(\#.*)$//) { - $anchor=$1; - } - my $srcHasQuestion = $src =~ /\?/; - $args->{"resourceLink"} = $src. - ($srcHasQuestion?'&':'?') . - 'symb=' . &Apache::lonnet::escape($curRes->shown_symb()). - $anchor; # Now, display each column. foreach my $col (@$cols) { @@ -1933,8 +1967,8 @@ sub add_linkitem { sub show_linkitems { my ($linkitems)=@_; - my @linkorder = ("launchnav","closenav","firsthomework","everything", - "uncompleted","changefolder","clearbubbles"); + my @linkorder = ("blank","launchnav","closenav","firsthomework", + "everything","uncompleted","changefolder","clearbubbles"); my $result .= (< @@ -2034,6 +2068,7 @@ See iterator documentation below. use strict; use GDBM_File; +use Apache::lonnet; sub new { # magic invocation to create a class instance @@ -2053,7 +2088,7 @@ sub new { my %navmaphash; my %parmhash; - my $courseFn = $ENV{"request.course.fn"}; + my $courseFn = $env{"request.course.fn"}; if (!(tie(%navmaphash, 'GDBM_File', "${courseFn}.db", &GDBM_READER(), 0640))) { return undef; @@ -2079,11 +2114,11 @@ sub generate_course_user_opt { my $self = shift; if ($self->{COURSE_USER_OPT_GENERATED}) { return; } - my $uname=$ENV{'user.name'}; - my $udom=$ENV{'user.domain'}; - my $uhome=$ENV{'user.home'}; - my $cid=$ENV{'request.course.id'}; - my $chome=$ENV{'course.'.$cid.'.home'}; + my $uname=$env{'user.name'}; + my $udom=$env{'user.domain'}; + my $uhome=$env{'user.home'}; + my $cid=$env{'request.course.id'}; + my $chome=$env{'course.'.$cid.'.home'}; my ($cdom,$cnum)=split(/\_/,$cid); my $userprefix=$uname.'_'.$udom.'_'; @@ -2139,18 +2174,18 @@ sub generate_email_discuss_status { my $symb = shift; if ($self->{EMAIL_DISCUSS_GENERATED}) { return; } - my $cid=$ENV{'request.course.id'}; + my $cid=$env{'request.course.id'}; my ($cdom,$cnum)=split(/\_/,$cid); my %emailstatus = &Apache::lonnet::dump('email_status'); my $logoutTime = $emailstatus{'logout'}; - my $courseLeaveTime = $emailstatus{'logout_'.$ENV{'request.course.id'}}; + my $courseLeaveTime = $emailstatus{'logout_'.$env{'request.course.id'}}; $self->{LAST_CHECK} = (($courseLeaveTime > $logoutTime) ? $courseLeaveTime : $logoutTime); my %discussiontime = &Apache::lonnet::dump('discussiontimes', $cdom, $cnum); my %lastread = &Apache::lonnet::dump('nohist_'.$cid.'_discuss', - $ENV{'user.domain'},$ENV{'user.name'},'lastread'); + $env{'user.domain'},$env{'user.name'},'lastread'); my %lastreadtime = (); foreach (keys %lastread) { my $key = $_; @@ -2161,9 +2196,9 @@ sub generate_email_discuss_status { my %feedback=(); my %error=(); my $keys = &Apache::lonnet::reply('keys:'. - $ENV{'user.domain'}.':'. - $ENV{'user.name'}.':nohist_email', - $ENV{'user.home'}); + $env{'user.domain'}.':'. + $env{'user.name'}.':nohist_email', + $env{'user.home'}); foreach my $msgid (split(/\&/, $keys)) { $msgid=&Apache::lonnet::unescape($msgid); @@ -2197,9 +2232,9 @@ sub get_user_data { if ($self->{RETRIEVED_USER_DATA}) { return; } # Retrieve performance data on problems - my %student_data = Apache::lonnet::currentdump($ENV{'request.course.id'}, - $ENV{'user.domain'}, - $ENV{'user.name'}); + my %student_data = Apache::lonnet::currentdump($env{'request.course.id'}, + $env{'user.domain'}, + $env{'user.name'}); $self->{STUDENT_DATA} = \%student_data; $self->{RETRIEVED_USER_DATA} = 1; @@ -2224,7 +2259,7 @@ sub navhash { # Checks to see if coursemap is defined, matching test in old lonnavmaps sub courseMapDefined { my $self = shift; - my $uri = &Apache::lonnet::clutter($ENV{'request.course.uri'}); + my $uri = &Apache::lonnet::clutter($env{'request.course.uri'}); my $firstres = $self->navhash("map_start_$uri"); my $lastres = $self->navhash("map_finish_$uri"); @@ -2234,7 +2269,8 @@ sub courseMapDefined { sub getIterator { my $self = shift; my $iterator = Apache::lonnavmaps::iterator->new($self, shift, shift, - shift, undef, shift); + shift, undef, shift, + shift, shift); return $iterator; } @@ -2243,7 +2279,6 @@ sub getIterator { sub hasDiscussion { my $self = shift; my $symb = shift; - $self->generate_email_discuss_status(); if (!defined($self->{DISCUSSION_TIME})) { return 0; } @@ -2252,12 +2287,9 @@ sub hasDiscussion { # backward compatibility (bulletin boards used to be 'wrapped') my $ressymb = $symb; - if ($ressymb =~ m|adm/(\w+)/(\w+)/(\d+)/bulletinboard$|) { - unless ($ressymb =~ m|adm/wrapper/adm|) { - $ressymb = 'bulletin___'.$3.'___adm/wrapper/adm/'.$1.'/'.$2.'/'.$3.'/bulletinboard'; - } + if ($ressymb =~ m-___adm/\w+/\w+/\d+/bulletinboard$-) { + $ressymb = $self->wrap_symb($ressymb); } - if ( defined ( $self->{LAST_READ}->{$ressymb} ) ) { return $self->{DISCUSSION_TIME}->{$ressymb} > $self->{LAST_READ}->{$ressymb}; } else { @@ -2269,6 +2301,19 @@ sub hasDiscussion { # Private method: Does the given resource (as a symb string) have # current feedback? Returns the string in the feedback hash, which # will be false if it does not exist. + +sub wrap_symb { + my $self=shift; + my $symb = shift; + my $ressymb = $symb; + if ($ressymb =~ m-___(adm/\w+/\w+/)(\d+)(/bulletinboard)$-) { + unless ($ressymb =~ m|adm/wrapper/adm|) { + $ressymb = 'bulletin___'.$2.'___adm/wrapper/'.$1.$2.$3; + } + } + return $ressymb; +} + sub getFeedback { my $self = shift; my $symb = shift; @@ -2364,7 +2409,7 @@ resource in the navmap. sub firstResource { my $self = shift; my $firstResource = $self->navhash('map_start_' . - &Apache::lonnet::clutter($ENV{'request.course.uri'})); + &Apache::lonnet::clutter($env{'request.course.uri'})); return $self->getById($firstResource); } @@ -2380,7 +2425,7 @@ in the navmap. sub finishResource { my $self = shift; my $firstResource = $self->navhash('map_finish_' . - &Apache::lonnet::clutter($ENV{'request.course.uri'})); + &Apache::lonnet::clutter($env{'request.course.uri'})); return $self->getById($firstResource); } @@ -2407,10 +2452,10 @@ sub parmval_real { # Make sure the {USER_OPT} and {COURSE_OPT} hashes are populated $self->generate_course_user_opt(); - my $cid=$ENV{'request.course.id'}; - my $csec=$ENV{'request.course.sec'}; - my $uname=$ENV{'user.name'}; - my $udom=$ENV{'user.domain'}; + my $cid=$env{'request.course.id'}; + my $csec=$env{'request.course.sec'}; + my $uname=$env{'user.name'}; + my $udom=$env{'user.domain'}; unless ($symb) { return ''; } my $result=''; @@ -2454,8 +2499,6 @@ sub parmval_real { if (defined($courseopt)) { if (defined($$courseopt{$courselevelr})) { return $$courseopt{$courselevelr}; } - if (defined($$courseopt{$courselevelm})) { return $$courseopt{$courselevelm}; } - if (defined($$courseopt{$courselevel})) { return $$courseopt{$courselevel}; } } # ----------------------------------------------------- third, check map parms @@ -2472,7 +2515,13 @@ sub parmval_real { $default=&Apache::lonnet::metadata($fn,'parameter_'.$meta_rwhat); if (defined($default)) { return $default} -# --------------------------------------------------- fifth , cascade up parts +# --------------------------------------------------- fifth, check more course + if (defined($courseopt)) { + if (defined($$courseopt{$courselevelm})) { return $$courseopt{$courselevelm}; } + if (defined($$courseopt{$courselevel})) { return $$courseopt{$courselevel}; } + } + +# --------------------------------------------------- sixth , cascade up parts my ($space,@qualifier)=split(/\./,$rwhat); my $qualifier=join('.',@qualifier); @@ -2501,7 +2550,7 @@ you're not sure if $res is already an ob resource appears multiple times in the course, only the first instance will be returned. As a result, this is probably useful only for maps. -=item * B(map, filterFunc, recursive, bailout): +=item * B(map, filterFunc, recursive, bailout, showall): The map is a specification of a map to retreive the resources from, either as a url or as an object. The filterFunc is a reference to a @@ -2509,13 +2558,14 @@ function that takes a resource object as true if the resource should be included, or false if it should not be. If recursive is true, the map will be recursively examined, otherwise it will not be. If bailout is true, the function will return -as soon as it finds a resource, if false it will finish. By default, -the map is the top-level map of the course, filterFunc is a function -that always returns 1, recursive is true, bailout is false. The -resources will be returned in a list containing the resource objects -for the corresponding resources, with B in -the list; regardless of branching, recursion, etc., it will be a flat -list. +as soon as it finds a resource, if false it will finish. If showall is +true it will not hide maps that contain nothing but one other map. By +default, the map is the top-level map of the course, filterFunc is a +function that always returns 1, recursive is true, bailout is false, +showall is false. The resources will be returned in a list containing +the resource objects for the corresponding resources, with B in the list; regardless of branching, +recursion, etc., it will be a flat list. Thus, this is suitable for cases where you don't want the structure, just a list of all resources. It is also suitable for finding out how @@ -2524,11 +2574,11 @@ want to know is if I resources matc parameter will allow you to avoid potentially expensive enumeration of all matching resources. -=item * B(map, filterFunc, recursive): +=item * B(map, filterFunc, recursive, showall): Convience method for - scalar(retrieveResources($map, $filterFunc, $recursive, 1)) > 0 + scalar(retrieveResources($map, $filterFunc, $recursive, 1, $showall)) > 0 which will tell whether the map has resources matching the description in the filter function. @@ -2562,7 +2612,7 @@ sub retrieveResources { if (!defined($recursive)) { $recursive = 1; } my $bailout = shift; if (!defined($bailout)) { $bailout = 0; } - + my $showall = shift; # Create the necessary iterator. if (!ref($map)) { # assume it's a url of a map. $map = $self->getResourceByUrl($map); @@ -2581,7 +2631,7 @@ sub retrieveResources { # Get an iterator. my $it = $self->getIterator($map->map_start(), $map->map_finish(), - undef, $recursive); + undef, $recursive, $showall); my @resources = (); @@ -2611,14 +2661,17 @@ sub hasResource { my $map = shift; my $filterFunc = shift; my $recursive = shift; + my $showall = shift; - return scalar($self->retrieveResources($map, $filterFunc, $recursive, 1)) > 0; + return scalar($self->retrieveResources($map, $filterFunc, $recursive, 1, $showall)) > 0; } 1; package Apache::lonnavmaps::iterator; use WeakRef; +use Apache::lonnet; + =pod =back @@ -2878,7 +2931,8 @@ sub new { Apache::lonnavmaps::iterator->new($self->{NAV_MAP}, $firstResource, $finishResource, $self->{FILTER}, $self->{ALREADY_SEEN}, - $self->{CONDITION}, 0); + $self->{CONDITION}, + $self->{FORCE_TOP}); } @@ -3041,7 +3095,9 @@ sub next { $self->{RECURSIVE_ITERATOR} = Apache::lonnavmaps::iterator->new($self->{NAV_MAP}, $firstResource, $finishResource, $self->{FILTER}, - $self->{ALREADY_SEEN}, $self->{CONDITION}); + $self->{ALREADY_SEEN}, + $self->{CONDITION}, + $self->{FORCE_TOP}); } # If this is a blank resource, don't actually return it. @@ -3095,6 +3151,8 @@ sub populateStack { package Apache::lonnavmaps::DFSiterator; use WeakRef; +use Apache::lonnet; + # Not documented in the perldoc: This is a simple iterator that just walks # through the nav map and presents the resources in a depth-first search # fashion, ignorant of conditionals, randomized resources, etc. It presents @@ -3480,12 +3538,16 @@ sub symb { . '___' . $second . '___' . $symbSrc; return &Apache::lonnet::symbclean($symb); } +sub wrap_symb { + my $self = shift; + return $self->{NAV_MAP}->wrap_symb($self->symb()); +} sub title { my $self=shift; if ($self->{ID} eq '0.0') { # If this is the top-level map, return the title of the course # since this map can not be titled otherwise. - return $ENV{'course.'.$ENV{'request.course.id'}.'.description'}; + return $env{'course.'.$env{'request.course.id'}.'.description'}; } return $self->navHash("title_", 1); } # considered private and undocumented @@ -3819,9 +3881,9 @@ sub weight { my $self = shift; my $part = shift; if (!defined($part)) { $part = '0'; } return &Apache::lonnet::EXT('resource.'.$part.'.weight', - $self->symb(), $ENV{'user.domain'}, - $ENV{'user.name'}, - $ENV{'request.course.sec'}); + $self->symb(), $env{'user.domain'}, + $env{'user.name'}, + $env{'request.course.sec'}); } sub part_display { my $self= shift(); my $partID = shift(); @@ -4702,7 +4764,8 @@ sub browsePriv { return $self->{BROWSE_PRIV}; } - $self->{BROWSE_PRIV} = &Apache::lonnet::allowed('bre', $self->src()); + $self->{BROWSE_PRIV} = &Apache::lonnet::allowed('bre',$self->src(), + $self->symb()); } =pod
'. &Apache::loncommon::help_open_menu('','Navigation Screen','Navigation_Screen','',undef,'RAT').' 
   '.$args->{'sort_html'}.'