version 1.496, 2013/05/30 05:04:22
|
version 1.509.2.14.2.5, 2023/01/18 00:53:39
|
Line 486 use Apache::lonlocal;
|
Line 486 use Apache::lonlocal;
|
use Apache::lonnet; |
use Apache::lonnet; |
use Apache::lonmap; |
use Apache::lonmap; |
|
|
use POSIX qw (floor strftime); |
use POSIX qw (ceil floor strftime); |
use Time::HiRes qw( gettimeofday tv_interval ); |
use Time::HiRes qw( gettimeofday tv_interval ); |
use LONCAPA; |
use LONCAPA; |
use DateTime(); |
use DateTime(); |
Line 494 use HTML::Entities;
|
Line 494 use HTML::Entities;
|
|
|
# For debugging |
# For debugging |
|
|
use Data::Dumper; |
#use Data::Dumper; |
|
|
|
|
# symbolic constants |
# symbolic constants |
Line 577 sub getLinkForResource {
|
Line 577 sub getLinkForResource {
|
my $anchor; |
my $anchor; |
if ($res->is_page()) { |
if ($res->is_page()) { |
foreach my $item (@$stack) { if (defined($item)) { $anchor = $item; } } |
foreach my $item (@$stack) { if (defined($item)) { $anchor = $item; } } |
$anchor=&escape($anchor->shown_symb()); |
if ($anchor->encrypted() && !&advancedUser()) { |
|
$anchor='LC_'.$anchor->id(); |
|
} else { |
|
$anchor=&escape($anchor->shown_symb()); |
|
} |
return ($res->link(),$res->shown_symb(),$anchor); |
return ($res->link(),$res->shown_symb(),$anchor); |
} |
} |
# in case folder was skipped over as "only sequence" |
# in case folder was skipped over as "only sequence" |
Line 624 sub getDescription {
|
Line 628 sub getDescription {
|
if ($status == $res->OPEN_LATER) { |
if ($status == $res->OPEN_LATER) { |
return &mt("Open [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($open,'start'),$res->symb(),'opendate',$part)); |
return &mt("Open [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($open,'start'),$res->symb(),'opendate',$part)); |
} |
} |
|
my $slotinfo; |
if ($res->simpleStatus($part) == $res->OPEN) { |
if ($res->simpleStatus($part) == $res->OPEN) { |
unless (&Apache::lonnet::allowed('mgr',$env{'request.course.id'})) { |
unless (&Apache::lonnet::allowed('mgr',$env{'request.course.id'})) { |
my ($slot_status,$slot_time,$slot_name)=$res->check_for_slot($part); |
my ($slot_status,$slot_time,$slot_name)=$res->check_for_slot($part); |
|
my $slotmsg; |
if ($slot_status == $res->UNKNOWN) { |
if ($slot_status == $res->UNKNOWN) { |
return &mt('Reservation status unknown'); |
$slotmsg = &mt('Reservation status unknown'); |
} elsif ($slot_status == $res->RESERVED) { |
} elsif ($slot_status == $res->RESERVED) { |
return &mt('Reserved - ends [_1]', |
$slotmsg = &mt('Reserved - ends [_1]', |
timeToHumanString($slot_time,'end')); |
timeToHumanString($slot_time,'end')); |
} elsif ($slot_status == $res->RESERVED_LOCATION) { |
} elsif ($slot_status == $res->RESERVED_LOCATION) { |
return &mt('Reserved - specific location(s) - ends [_1]', |
$slotmsg = &mt('Reserved - specific location(s) - ends [_1]', |
timeToHumanString($slot_time,'end')); |
timeToHumanString($slot_time,'end')); |
} elsif ($slot_status == $res->RESERVED_LATER) { |
} elsif ($slot_status == $res->RESERVED_LATER) { |
return &mt('Reserved - next open [_1]', |
$slotmsg = &mt('Reserved - next open [_1]', |
timeToHumanString($slot_time,'start')); |
timeToHumanString($slot_time,'start')); |
} elsif ($slot_status == $res->RESERVABLE) { |
} elsif ($slot_status == $res->RESERVABLE) { |
return &mt('Reservable, reservations close [_1]', |
$slotmsg = &mt('Reservable, reservations close [_1]', |
|
timeToHumanString($slot_time,'end')); |
|
} elsif ($slot_status == $res->NEEDS_CHECKIN) { |
|
$slotmsg = &mt('Reserved, check-in needed - ends [_1]', |
timeToHumanString($slot_time,'end')); |
timeToHumanString($slot_time,'end')); |
} elsif ($slot_status == $res->RESERVABLE_LATER) { |
} elsif ($slot_status == $res->RESERVABLE_LATER) { |
return &mt('Reservable, reservations open [_1]', |
$slotmsg = &mt('Reservable, reservations open [_1]', |
timeToHumanString($slot_time,'start')); |
timeToHumanString($slot_time,'start')); |
} elsif ($slot_status == $res->NOT_IN_A_SLOT) { |
} elsif ($slot_status == $res->NOT_IN_A_SLOT) { |
return &mt('Reserve a time/place to work'); |
$slotmsg = &mt('Reserve a time/place to work'); |
} elsif ($slot_status == $res->NOTRESERVABLE) { |
} elsif ($slot_status == $res->NOTRESERVABLE) { |
return &mt('Reservation not available'); |
$slotmsg = &mt('Reservation not available'); |
} elsif ($slot_status == $res->WAITING_FOR_GRADE) { |
} elsif ($slot_status == $res->WAITING_FOR_GRADE) { |
return &mt('Submission in grading queue'); |
$slotmsg = &mt('Submission in grading queue'); |
|
} |
|
if ($slotmsg) { |
|
if ($res->is_task() || !$due) { |
|
return $slotmsg; |
|
} |
|
$slotinfo = (' ' x 2).'('.$slotmsg.')'; |
} |
} |
} |
} |
} |
} |
if ($status == $res->OPEN) { |
if ($status == $res->OPEN) { |
if ($due) { |
if ($due) { |
if ($res->is_practice()) { |
if ($res->is_practice()) { |
return &mt("Closes [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'start'),$res->symb(),'duedate',$part)); |
return &mt("Closes [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'start'),$res->symb(),'duedate',$part)).$slotinfo; |
} else { |
} else { |
return &mt("Due [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'end'),$res->symb(),'duedate',$part)); |
return &mt("Due [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'end'),$res->symb(),'duedate',$part)).$slotinfo; |
} |
} |
} else { |
} else { |
return &Apache::lonhtmlcommon::direct_parm_link(&mt("Open, no due date"),$res->symb(),'duedate',$part); |
return &Apache::lonhtmlcommon::direct_parm_link(&mt("Open, no due date"),$res->symb(),'duedate',$part).$slotinfo; |
} |
} |
} |
} |
if ($status == $res->PAST_DUE_ANSWER_LATER) { |
if ($status == $res->PAST_DUE_ANSWER_LATER) { |
Line 907 sub render_resource {
|
Line 922 sub render_resource {
|
my $nonLinkedText = ''; # stuff after resource title not in link |
my $nonLinkedText = ''; # stuff after resource title not in link |
|
|
my $link = $params->{"resourceLink"}; |
my $link = $params->{"resourceLink"}; |
|
if ($resource->ext()) { |
|
$link =~ s/\#.+(\?)/$1/g; |
|
} |
|
|
# The URL part is not escaped at this point, but the symb is... |
# The URL part is not escaped at this point, but the symb is... |
|
|
Line 927 sub render_resource {
|
Line 945 sub render_resource {
|
# links to open and close the folder |
# links to open and close the folder |
|
|
my $whitespace = $location.'/whitespace_21.gif'; |
my $whitespace = $location.'/whitespace_21.gif'; |
my $linkopen = "<img src='$whitespace' alt='' />"."<a href=\"$link\">"; |
my ($nomodal,$linkopen,$linkclose); |
my $linkclose = "</a>"; |
unless ($resource->is_map() || $params->{'resource_nolink'}) { |
|
$linkopen = "<img src='$whitespace' alt='' />"; |
|
$linkclose = "</a>"; |
|
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 .= "<a href=\"#\" onclick=\"javascript:window.open('$esclink','resourcepreview','height=400,width=500,scrollbars=1,resizable=1,menubar=0,location=1'); return false;\" />"; |
|
} else { |
|
$linkopen .= "<a href=\"$link\" onclick=\"javascript:openMyModal('$esclink',600,500,'yes','true'); return false;\">"; |
|
} |
|
} else { |
|
$linkopen .= "<a href=\"$link\">"; |
|
} |
|
} |
|
|
# Default icon: unknown page |
# Default icon: unknown page |
my $icon = "<img class=\"LC_contentImage\" src='$location/unknown.gif' alt='' />"; |
my $icon = "<img class=\"LC_contentImage\" src='$location/unknown.gif' alt='' />"; |
Line 956 sub render_resource {
|
Line 997 sub render_resource {
|
if ($it->{CONDITION}) { |
if ($it->{CONDITION}) { |
$nowOpen = !$nowOpen; |
$nowOpen = !$nowOpen; |
} |
} |
|
my $folderType; |
my $folderType = $resource->is_sequence() ? 'folder' : 'page'; |
if (&advancedUser() && $resource->is_missing_map()) { |
|
$folderType = 'none'; |
|
} else { |
|
$folderType = $resource->is_sequence() ? 'folder' : 'page'; |
|
} |
my $title=$resource->title; |
my $title=$resource->title; |
$title=~s/\"/\&qout;/g; |
$title=~s/\"/\&qout;/g; |
if (!$params->{'resource_no_folder_link'}) { |
if (!$params->{'resource_no_folder_link'}) { |
Line 976 sub render_resource {
|
Line 1021 sub render_resource {
|
'&jump=' . |
'&jump=' . |
&escape($resource->symb()) . |
&escape($resource->symb()) . |
"&folderManip=1\">"; |
"&folderManip=1\">"; |
|
$linkclose = '</a>'; |
} else { |
} else { |
# Don't allow users to manipulate folder |
# Don't allow users to manipulate folder |
$icon = "navmap.$folderType." . ($nowOpen ? 'closed' : 'open') . '.gif'; |
$icon = "navmap.$folderType." . ($nowOpen ? 'closed' : 'open') . '.gif'; |
$icon = "<img class=\"LC_space\" src='$whitespace' alt='' />"."<img class=\"LC_contentImage\" src='$location/$icon' alt=\"".($nowOpen ? &mt('Open Folder') : &mt('Close Folder')).' '.$title."\" />"; |
$icon = "<img class=\"LC_space\" src='$whitespace' alt='' />"."<img class=\"LC_contentImage\" src='$location/$icon' alt=\"".($nowOpen ? &mt('Open Folder') : &mt('Close Folder')).' '.$title."\" />"; |
|
if ($params->{'caller'} eq 'sequence') { |
$linkopen = ""; |
$linkopen = "<a href=\"$link\">"; |
$linkclose = ""; |
$linkclose = '</a>'; |
|
} else { |
|
$linkopen = ""; |
|
$linkclose = ""; |
|
} |
} |
} |
if ((&Apache::lonnet::allowed('mdc',$env{'request.course.id'})) && |
if (((&Apache::lonnet::allowed('mdc',$env{'request.course.id'})) || |
|
(&Apache::lonnet::allowed('cev',$env{'request.course.id'}))) && |
($resource->symb=~/\_\_\_[^\_]+\_\_\_uploaded/)) { |
($resource->symb=~/\_\_\_[^\_]+\_\_\_uploaded/)) { |
if (!$params->{'map_no_edit_link'}) { |
if (!$params->{'map_no_edit_link'}) { |
my $icon = &Apache::loncommon::lonhttpdurl('/res/adm/pages').'/editmap.png'; |
my $icon = &Apache::loncommon::lonhttpdurl('/res/adm/pages').'/editmap.png'; |
Line 995 sub render_resource {
|
Line 1045 sub render_resource {
|
'</a>'; |
'</a>'; |
} |
} |
} |
} |
} |
if ($params->{'mapHidden'} || $resource->randomout()) { |
|
$nonLinkedText .= ' <span class="LC_warning">('.&mt('hidden').')</span> '; |
if ($resource->randomout()) { |
} elsif ($params->{'mapUnlisted'}) { |
$nonLinkedText .= ' <span class="LC_warning">('.&mt('hidden').')</span> '; |
$nonLinkedText .= ' <span class="LC_warning">('.&mt('unlisted').')</span> '; |
|
} elsif ($params->{'mapHiddenDeepLink'} || $resource->deeplinkout()) { |
|
$nonLinkedText .= ' <span class="LC_warning">('.&mt('not shown').')</span> '; |
|
} |
|
} else { |
|
if ($resource->randomout()) { |
|
$nonLinkedText .= ' <span class="LC_warning">('.&mt('hidden').')</span> '; |
|
} elsif ($resource->deeplinkout()) { |
|
$nonLinkedText .= ' <span class="LC_warning">('.&mt('not shown').')</span> '; |
|
} else { |
|
my $deeplink = $resource->deeplink($params->{caller}); |
|
if ((($deeplink eq 'absent') || ($deeplink eq 'grades')) && |
|
&advancedUser()) { |
|
$nonLinkedText .= ' <span class="LC_warning">('.&mt('unlisted').')</span> '; |
|
} elsif (($deeplink) && ($deeplink) ne 'full') { |
|
if (&advancedUser()) { |
|
$nonLinkedText .= ' <span class="LC_warning">('.&mt('deep-link access'). |
|
')</span> '; |
|
} else { |
|
$nonLinkedText .= ' <span class="LC_warning">('.&mt('access via external site'). |
|
')</span> '; |
|
} |
|
} |
|
} |
} |
} |
if (!$resource->condval()) { |
if (!$resource->condval()) { |
$nonLinkedText .= ' <span class="LC_info">('.&mt('conditionally hidden').')</span> '; |
$nonLinkedText .= ' <span class="LC_info">('.&mt('conditionally hidden').')</span> '; |
Line 1048 sub render_resource {
|
Line 1121 sub render_resource {
|
} |
} |
|
|
if (!$params->{'resource_nolink'} && !$resource->is_sequence() && !$resource->is_empty_sequence) { |
if (!$params->{'resource_nolink'} && !$resource->is_sequence() && !$resource->is_empty_sequence) { |
$result .= "$curMarkerBegin<a href=\"$link\">$title$partLabel</a>$curMarkerEnd$editmapLink$nonLinkedText</td>"; |
$linkclose = '</a>'; |
} else { |
if ($params->{'modalLink'}) { |
$result .= "$curMarkerBegin$linkopen$title$partLabel</a>$curMarkerEnd$editmapLink$nonLinkedText</td>"; |
my $esclink = &js_escape($link); |
|
if ($nomodal) { |
|
$linkopen = "<a href=\"#\" onclick=\"javascript:window.open('$esclink','resourcepreview','height=400,width=500,scrollbars=1,resizable=1,menubar=0,location=1'); return false;\" />"; |
|
} else { |
|
$linkopen = "<a href=\"$link\" onclick=\"javascript:openMyModal('$esclink',600,500,'yes','true'); return false;\">"; |
|
} |
|
} else { |
|
$linkopen = "<a href=\"$link\">"; |
|
} |
} |
} |
|
$result .= "$curMarkerBegin$linkopen$title$partLabel$linkclose$curMarkerEnd$editmapLink$nonLinkedText</td>"; |
|
|
return $result; |
return $result; |
} |
} |
Line 1140 sub render_long_status {
|
Line 1222 sub render_long_status {
|
my $info = ''; |
my $info = ''; |
if ($resource->is_problem() || $resource->is_practice()) { |
if ($resource->is_problem() || $resource->is_practice()) { |
$color = $colormap{$resource->status}; |
$color = $colormap{$resource->status}; |
|
|
if (dueInLessThan24Hours($resource, $part) || |
if (dueInLessThan24Hours($resource, $part)) { |
lastTry($resource, $part)) { |
|
$color = $hurryUpColor; |
$color = $hurryUpColor; |
$info = ' title="'.&mt('Due in less than 24 hours!').'"'; |
$info = ' title="'.&mt('Due in less than 24 hours!').'"'; |
} |
} elsif (lastTry($resource, $part)) { |
|
unless (($resource->problemstatus($part) eq 'no') || |
|
($resource->problemstatus($part) eq 'no_feedback_ever')) { |
|
$color = $hurryUpColor; |
|
$info = ' title="'.&mt('One try remaining!').'"'; |
|
} |
|
} |
} |
} |
|
|
if ($resource->kind() eq "res" && |
if ($resource->kind() eq "res" && |
Line 1308 sub render {
|
Line 1395 sub render {
|
# an infinite loop |
# an infinite loop |
my $oldFilterFunc = $filterFunc; |
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') && |
|
!$res->deeplinkout() && |
&$oldFilterFunc($res);}; |
&$oldFilterFunc($res);}; |
} |
} |
|
|
my $condition = 0; |
my $condition = 0; |
if ($env{'form.condition'}) { |
if ($env{'form.condition'}) { |
$condition = 1; |
$condition = 1; |
|
} elsif (($env{'request.deeplink.login'}) && ($env{'request.course.id'}) && (!$userCanSeeHidden)) { |
|
if (!defined($navmap)) { |
|
$navmap = Apache::lonnavmaps::navmap->new(); |
|
} |
|
if (defined($navmap)) { |
|
my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; |
|
my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; |
|
my $symb = &Apache::loncommon::symb_from_tinyurl($env{'request.deeplink.login'},$cnum,$cdom); |
|
if ($symb) { |
|
my $deeplink; |
|
my $res = $navmap->getBySymb($symb); |
|
if ($res->is_map()) { |
|
my $mapname = &Apache::lonnet::declutter($res->src()); |
|
$mapname = &Apache::lonnet::deversion($mapname); |
|
$deeplink = $navmap->get_mapparam(undef,$mapname,"0.deeplink"); |
|
} else { |
|
$deeplink = $res->deeplink(); |
|
} |
|
if ($deeplink ne '') { |
|
if ((split(/,/,$deeplink))[1] eq 'hide') { |
|
if ($res->is_map()) { |
|
map { $filterHash->{$_} = 1 if $_ } split(/,/,$res->map_hierarchy()); |
|
} else { |
|
my $mapurl = (&Apache::lonnet::decode_symb($symb))[0]; |
|
my $map = $navmap->getResourceByUrl($mapurl); |
|
map { $filterHash->{$_} = 1 if $_ } split(/,/,$map->map_hierarchy()); |
|
} |
|
} |
|
} |
|
} |
|
} |
} |
} |
|
|
if (!$env{'form.folderManip'} && !defined($args->{'iterator'})) { |
if (!$env{'form.folderManip'} && !defined($args->{'iterator'}) && !$args->{'nocurrloc'}) { |
# Step 1: Check to see if we have a navmap |
# Step 1: Check to see if we have a navmap |
if (!defined($navmap)) { |
if (!defined($navmap)) { |
$navmap = Apache::lonnavmaps::navmap->new(); |
$navmap = Apache::lonnavmaps::navmap->new(); |
Line 1337 sub render {
|
Line 1458 sub render {
|
my $currenturl = $env{'form.postdata'}; |
my $currenturl = $env{'form.postdata'}; |
#$currenturl=~s/^http\:\/\///; |
#$currenturl=~s/^http\:\/\///; |
#$currenturl=~s/^[^\/]+//; |
#$currenturl=~s/^[^\/]+//; |
|
unless ($args->{'caller'} eq 'sequence') { |
$here = $jump = &Apache::lonnet::symbread($currenturl); |
$here = $jump = &Apache::lonnet::symbread($currenturl); |
|
} |
} |
} |
if ($here eq '') { |
if (($here eq '') && ($args->{'caller'} ne 'sequence')) { |
my $last; |
my $last; |
if (tie(my %hash,'GDBM_File',$env{'request.course.fn'}.'_symb.db', |
if (tie(my %hash,'GDBM_File',$env{'request.course.fn'}.'_symb.db', |
&GDBM_READER(),0640)) { |
&GDBM_READER(),0640)) { |
Line 1400 sub render {
|
Line 1522 sub render {
|
if ($args->{'iterator_map'}) { |
if ($args->{'iterator_map'}) { |
my $map = $args->{'iterator_map'}; |
my $map = $args->{'iterator_map'}; |
$map = $navmap->getResourceByUrl($map); |
$map = $navmap->getResourceByUrl($map); |
my $firstResource = $map->map_start(); |
if (ref($map)) { |
my $finishResource = $map->map_finish(); |
my $firstResource = $map->map_start(); |
|
my $finishResource = $map->map_finish(); |
$args->{'iterator'} = $it = $navmap->getIterator($firstResource, $finishResource, $filterHash, $condition); |
$args->{'iterator'} = $it = $navmap->getIterator($firstResource, $finishResource, $filterHash, $condition); |
|
} else { |
|
return; |
|
} |
} else { |
} else { |
$args->{'iterator'} = $it = $navmap->getIterator(undef, undef, $filterHash, $condition,undef,$args->{'include_top_level_map'}); |
$args->{'iterator'} = $it = $navmap->getIterator(undef, undef, $filterHash, $condition,undef,$args->{'include_top_level_map'}); |
} |
} |
Line 1521 END
|
Line 1646 END
|
} |
} |
$result.='</form>'; |
$result.='</form>'; |
} |
} |
if (($args->{'caller'} eq 'navmapsdisplay') && |
if (($args->{'caller'} eq 'navmapsdisplay') && ($env{'request.course.id'})) { |
(&Apache::lonnet::allowed('mdc',$env{'request.course.id'}))) { |
|
my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; |
my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; |
my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; |
my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; |
if ($env{'course.'.$env{'request.course.id'}.'.url'} eq |
if ($env{'course.'.$env{'request.course.id'}.'.url'} eq |
"uploaded/$cdom/$cnum/default.sequence") { |
"uploaded/$cdom/$cnum/default.sequence") { |
&add_linkitem($args->{'linkitems'},'edittoplevel', |
if ((&Apache::lonnet::allowed('mdc',$env{'request.course.id'})) || |
"javascript:gocmd('/adm/coursedocs','editdocs');", |
(&Apache::lonnet::allowed('cev',$env{'request.course.id'}))) { |
'Content Editor'); |
&add_linkitem($args->{'linkitems'},'edittoplevel', |
|
"javascript:gocmd('/adm/coursedocs','editdocs');", |
|
'Content Editor'); |
|
} |
|
if ($counter) { |
|
&add_linkitem($args->{'linkitems'},'printout', |
|
"javascript:gopost('/adm/printout','/adm/navmaps');", |
|
'Prepare a printable document'); |
|
} |
} |
} |
} |
} |
|
|
Line 1568 END
|
Line 1700 END
|
$args->{'indentString'} = setDefault($args->{'indentString'}, "<img src='$location' alt='' />"); |
$args->{'indentString'} = setDefault($args->{'indentString'}, "<img src='$location' alt='' />"); |
$args->{'displayedHereMarker'} = 0; |
$args->{'displayedHereMarker'} = 0; |
|
|
# If we're suppressing empty sequences, look for them here. Use DFS for speed, |
# If we're suppressing empty sequences, look for them here. |
# since structure actually doesn't matter, except what map has what resources. |
# We also do this even if $args->{'suppressEmptySequences'} |
if ($args->{'suppressEmptySequences'}) { |
# is not true, so we can hide empty sequences for which the |
my $dfsit = Apache::lonnavmaps::DFSiterator->new($navmap, |
# hiddenresource parameter is set to yes (at map level), or |
$it->{FIRST_RESOURCE}, |
# mark as hidden for users who have $userCanSeeHidden. |
$it->{FINISH_RESOURCE}, |
# Use DFS for speed, since structure actually doesn't matter, |
{}, undef, 1); |
# except what map has what resources. |
my $depth = 0; |
|
$dfsit->next(); |
my $dfsit = Apache::lonnavmaps::DFSiterator->new($navmap, |
my $curRes = $dfsit->next(); |
$it->{FIRST_RESOURCE}, |
while ($depth > -1) { |
$it->{FINISH_RESOURCE}, |
if ($curRes == $dfsit->BEGIN_MAP()) { $depth++; } |
{}, undef, 1); |
if ($curRes == $dfsit->END_MAP()) { $depth--; } |
|
|
my $depth = 0; |
if (ref($curRes)) { |
$dfsit->next(); |
# Parallel pre-processing: Do sequences have non-filtered-out children? |
my $curRes = $dfsit->next(); |
if ($curRes->is_map()) { |
while ($depth > -1) { |
$curRes->{DATA}->{HAS_VISIBLE_CHILDREN} = 0; |
if ($curRes == $dfsit->BEGIN_MAP()) { $depth++; } |
# Sequences themselves do not count as visible children, |
if ($curRes == $dfsit->END_MAP()) { $depth--; } |
# unless those sequences also have visible children. |
|
# This means if a sequence appears, there's a "promise" |
if (ref($curRes)) { |
# that there's something under it if you open it, somewhere. |
# Parallel pre-processing: Do sequences have non-filtered-out children? |
} else { |
if ($curRes->is_map()) { |
# Not a sequence: if it's filtered, ignore it, otherwise |
$curRes->{DATA}->{HAS_VISIBLE_CHILDREN} = 0; |
# rise up the stack and mark the sequences as having children |
# Sequences themselves do not count as visible children, |
if (&$filterFunc($curRes)) { |
# unless those sequences also have visible children. |
for my $sequence (@{$dfsit->getStack()}) { |
# This means if a sequence appears, there's a "promise" |
$sequence->{DATA}->{HAS_VISIBLE_CHILDREN} = 1; |
# that there's something under it if you open it, somewhere. |
} |
} elsif ($curRes->src()) { |
|
# Not a sequence: if it's filtered, ignore it, otherwise |
|
# rise up the stack and mark the sequences as having children |
|
if (&$filterFunc($curRes)) { |
|
for my $sequence (@{$dfsit->getStack()}) { |
|
$sequence->{DATA}->{HAS_VISIBLE_CHILDREN} = 1; |
} |
} |
} |
} |
} |
} |
} continue { |
|
$curRes = $dfsit->next(); |
|
} |
} |
|
} continue { |
|
$curRes = $dfsit->next(); |
} |
} |
|
|
my $displayedJumpMarker = 0; |
my $displayedJumpMarker = 0; |
Line 1660 END
|
Line 1797 END
|
undef($args->{'sort'}); |
undef($args->{'sort'}); |
} |
} |
|
|
|
# Determine if page will be served with https in case |
|
# it contains a syllabus which uses an external URL |
|
# which points at an http site. |
|
|
|
my ($is_ssl,$cdom,$cnum,$hostname); |
|
if ($ENV{'SERVER_PORT'} == 443) { |
|
$is_ssl = 1; |
|
if ($r) { |
|
$hostname = $r->hostname(); |
|
} else { |
|
$hostname = $ENV{'SERVER_NAME'}; |
|
} |
|
} |
|
if ($env{'request.course.id'}) { |
|
$cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; |
|
$cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; |
|
} |
|
|
|
my $inhibitmenu; |
|
if ($args->{'modalLink'}) { |
|
$inhibitmenu = '&inhibitmenu=yes'; |
|
} |
|
|
while (1) { |
while (1) { |
if ($args->{'sort'}) { |
if ($args->{'sort'}) { |
Line 1695 END
|
Line 1854 END
|
} |
} |
|
|
# If this is an empty sequence and we're filtering them, continue on |
# If this is an empty sequence and we're filtering them, continue on |
if ($curRes->is_map() && $args->{'suppressEmptySequences'} && |
$args->{'mapHidden'} = 0; |
!$curRes->{DATA}->{HAS_VISIBLE_CHILDREN}) { |
$args->{'mapUnlisted'} = 0; |
next; |
$args->{'mapHiddenDeepLink'} = 0; |
|
if (($curRes->is_map()) && (!$curRes->{DATA}->{HAS_VISIBLE_CHILDREN})) { |
|
if ($args->{'suppressEmptySequences'}) { |
|
next; |
|
} else { |
|
my $mapname = &Apache::lonnet::declutter($curRes->src()); |
|
$mapname = &Apache::lonnet::deversion($mapname); |
|
if (lc($navmap->get_mapparam(undef,$mapname,"0.hiddenresource")) eq 'yes') { |
|
if ($userCanSeeHidden) { |
|
$args->{'mapHidden'} = 1; |
|
} else { |
|
next; |
|
} |
|
} elsif ($curRes->deeplinkout) { |
|
if ($userCanSeeHidden) { |
|
$args->{'mapHiddenDeepLink'} = 1; |
|
} else { |
|
next; |
|
} |
|
} else { |
|
my $deeplink = $navmap->get_mapparam(undef,$mapname,"0.deeplink"); |
|
my ($state,$others,$listed) = split(/,/,$deeplink); |
|
if (($listed eq 'absent') || ($listed eq 'grades')) { |
|
if ($userCanSeeHidden) { |
|
$args->{'mapUnlisted'} = 1; |
|
} else { |
|
next; |
|
} |
|
} |
|
} |
|
} |
} |
} |
|
|
# If we're suppressing navmaps and this is a navmap, continue on |
# If we're suppressing navmaps and this is a navmap, continue on |
Line 1758 END
|
Line 1947 END
|
$args->{'condensed'} = 1; |
$args->{'condensed'} = 1; |
} |
} |
} |
} |
} |
} |
|
# If deep-link parameter is set (and is not set to full) suppress link |
|
# unless privileged user, tinyurl used for login resolved to a map, and |
|
# the resource is within the map. |
|
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 the multipart problem was condensed, "forget" it was multipart |
if (scalar(@parts) == 1) { |
if (scalar(@parts) == 1) { |
Line 1781 END
|
Line 1979 END
|
$stack=$it->getStack(); |
$stack=$it->getStack(); |
} |
} |
($src,$symb,$anchor)=getLinkForResource($stack); |
($src,$symb,$anchor)=getLinkForResource($stack); |
|
my $srcHasQuestion = $src =~ /\?/; |
|
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://})) { |
|
unless ((&Apache::lonnet::uses_sts()) || (&Apache::lonnet::waf_allssl($hostname))) { |
|
if ($hostname ne '') { |
|
$src = 'http://'.$hostname.$src; |
|
} |
|
$src .= ($srcHasQuestion? '&' : '?') . 'usehttp=1'; |
|
$srcHasQuestion = 1; |
|
} |
|
} elsif (($is_ssl) && ($src =~ m{^\Q/adm/wrapper/ext/\E(?!https:)})) { |
|
unless ((&Apache::lonnet::uses_sts()) || (&Apache::lonnet::waf_allssl($hostname))) { |
|
if ($hostname ne '') { |
|
$src = 'http://'.$hostname.$src; |
|
} |
|
$src .= ($srcHasQuestion? '&' : '?') . 'usehttp=1'; |
|
$srcHasQuestion = 1; |
|
} |
|
} |
|
} |
if (defined($anchor)) { $anchor='#'.$anchor; } |
if (defined($anchor)) { $anchor='#'.$anchor; } |
my $srcHasQuestion = $src =~ /\?/; |
if (($args->{'caller'} eq 'sequence') && ($curRes->is_map())) { |
$args->{"resourceLink"} = $src. |
$args->{"resourceLink"} = $src.($srcHasQuestion?'&':'?') .'navmap=1'; |
($srcHasQuestion?'&':'?') . |
} else { |
'symb=' . &escape($symb).$anchor; |
$args->{"resourceLink"} = $src. |
|
($srcHasQuestion?'&':'?') . |
|
'symb=' . &escape($symb).$inhibitmenu.$anchor; |
|
} |
} |
} |
# Now, we've decided what parts to show. Loop through them and |
# Now, we've decided what parts to show. Loop through them and |
# show them. |
# show them. |
Line 1813 END
|
Line 2035 END
|
$currentJumpDelta) { |
$currentJumpDelta) { |
# Jam the anchor after the <td> tag; |
# Jam the anchor after the <td> tag; |
# necessary for valid HTML (which Mozilla requires) |
# necessary for valid HTML (which Mozilla requires) |
$colHTML =~ s/\>/\>\<a name="curloc" \/\>/; |
$colHTML =~ s/\>/\>\<a name="curloc" \>\<\/a\>/; |
$displayedJumpMarker = 1; |
$displayedJumpMarker = 1; |
} |
} |
$result .= $colHTML . "\n"; |
$result .= $colHTML . "\n"; |
Line 1887 sub show_linkitems_toolbar {
|
Line 2109 sub show_linkitems_toolbar {
|
$result .= '<td align="left">'."\n". |
$result .= '<td align="left">'."\n". |
'<ul id="LC_toolbar">'; |
'<ul id="LC_toolbar">'; |
my @linkorder = ('firsthomework','everything','uncompleted', |
my @linkorder = ('firsthomework','everything','uncompleted', |
'changefolder','clearbubbles','edittoplevel'); |
'changefolder','clearbubbles','printout','edittoplevel'); |
foreach my $link (@linkorder) { |
foreach my $link (@linkorder) { |
if (ref($args->{'linkitems'}{$link}) eq 'HASH') { |
if (ref($args->{'linkitems'}{$link}) eq 'HASH') { |
if ($args->{'linkitems'}{$link}{'text'} ne '') { |
if ($args->{'linkitems'}{$link}{'text'} ne '') { |
Line 2015 sub new {
|
Line 2237 sub new {
|
my $proto = shift; |
my $proto = shift; |
my $class = ref($proto) || $proto; |
my $class = ref($proto) || $proto; |
my $self = {}; |
my $self = {}; |
bless($self); # So we can call change_user if neceesary |
bless($self); # So we can call change_user if necessary |
|
|
$self->{USERNAME} = shift || $env{'user.name'}; |
$self->{USERNAME} = shift || $env{'user.name'}; |
$self->{DOMAIN} = shift || $env{'user.domain'}; |
$self->{DOMAIN} = shift || $env{'user.domain'}; |
Line 2034 sub new {
|
Line 2256 sub new {
|
|
|
# We can only tie the nav hash as done below if the username/domain |
# We can only tie the nav hash as done below if the username/domain |
# match the env one. Otherwise change_user does everything we need...since we can't |
# match the env one. Otherwise change_user does everything we need...since we can't |
# assume there are course hashes for the specific requested user@domamin: |
# assume there are course hashes for the specific requested user:domain |
|
# Note: change_user is also called if we need the nav hash when printing CODEd |
|
# assignments or printing an exam, in which the enclosing folder for the items in |
|
# the exam has hidden set. |
# |
# |
|
|
if (($self->{USERNAME} eq $env{'user.name'}) && ($self->{DOMAIN} eq $env{'user.domain'}) && !$self->{CODE}) { |
if (($self->{USERNAME} eq $env{'user.name'}) && ($self->{DOMAIN} eq $env{'user.domain'}) && |
|
!$self->{CODE} && !$self->{NOHIDE}) { |
|
|
# tie the nav hash |
# tie the nav hash |
|
|
Line 2108 sub change_user {
|
Line 2334 sub change_user {
|
$self->{PARM_CACHE} = {}; |
$self->{PARM_CACHE} = {}; |
|
|
my %parm_hash = {}; |
my %parm_hash = {}; |
foreach my $key (keys %big_hash) { |
foreach my $key (keys(%big_hash)) { |
if ($key =~ /^param\./) { |
if ($key =~ /^param\./) { |
my $param_key = $key; |
my $param_key = $key; |
$param_key =~ s/^param\.//; |
$param_key =~ s/^param\.//; |
Line 2118 sub change_user {
|
Line 2344 sub change_user {
|
|
|
$self->{PARM_HASH} = \%parm_hash; |
$self->{PARM_HASH} = \%parm_hash; |
|
|
|
} |
|
|
} |
|
|
|
sub generate_course_user_opt { |
sub generate_course_user_opt { |
my $self = shift; |
my $self = shift; |
Line 2183 sub generate_email_discuss_status {
|
Line 2407 sub generate_email_discuss_status {
|
my %lastread = &Apache::lonnet::dump('nohist_'.$cid.'_discuss', |
my %lastread = &Apache::lonnet::dump('nohist_'.$cid.'_discuss', |
$self->{DOMAIN},$self->{USERNAME},'lastread'); |
$self->{DOMAIN},$self->{USERNAME},'lastread'); |
my %lastreadtime = (); |
my %lastreadtime = (); |
foreach my $key (keys %lastread) { |
foreach my $key (keys(%lastread)) { |
my $shortkey = $key; |
my $shortkey = $key; |
$shortkey =~ s/_lastread$//; |
$shortkey =~ s/_lastread$//; |
$lastreadtime{$shortkey} = $lastread{$key}; |
$lastreadtime{$shortkey} = $lastread{$key}; |
Line 2197 sub generate_email_discuss_status {
|
Line 2421 sub generate_email_discuss_status {
|
foreach my $msgid (@keys) { |
foreach my $msgid (@keys) { |
if ((!$emailstatus{$msgid}) || ($emailstatus{$msgid} eq 'new')) { |
if ((!$emailstatus{$msgid}) || ($emailstatus{$msgid} eq 'new')) { |
my ($sendtime,$shortsubj,$fromname,$fromdomain,$status,$fromcid, |
my ($sendtime,$shortsubj,$fromname,$fromdomain,$status,$fromcid, |
$symb,$error) = &Apache::lonmsg::unpackmsgid($msgid); |
$symb,$error) = &Apache::lonmsg::unpackmsgid(&LONCAPA::escape($msgid)); |
&Apache::lonenc::check_decrypt(\$symb); |
&Apache::lonenc::check_decrypt(\$symb); |
if (($fromcid ne '') && ($fromcid ne $cid)) { |
if (($fromcid ne '') && ($fromcid ne $cid)) { |
next; |
next; |
Line 2298 sub getIterator {
|
Line 2522 sub getIterator {
|
my $self = shift; |
my $self = shift; |
my $iterator = Apache::lonnavmaps::iterator->new($self, shift, shift, |
my $iterator = Apache::lonnavmaps::iterator->new($self, shift, shift, |
shift, undef, shift, |
shift, undef, shift, |
shift, shift); |
shift, shift, shift); |
return $iterator; |
return $iterator; |
} |
} |
|
|
Line 2694 sub parmval_real {
|
Line 2918 sub parmval_real {
|
if (defined($pack_def)) { return [$pack_def,'resource']; } |
if (defined($pack_def)) { return [$pack_def,'resource']; } |
return ['']; |
return ['']; |
} |
} |
|
|
|
sub recurseup_maps { |
|
my ($self,$mapname) = @_; |
|
my @recurseup; |
|
if ($mapname) { |
|
my $res = $self->getResourceByUrl($mapname); |
|
if (ref($res)) { |
|
my @pcs = split(/,/,$res->map_hierarchy()); |
|
shift(@pcs); |
|
if (@pcs) { |
|
@recurseup = map { &Apache::lonnet::declutter($self->getByMapPc($_)->src()); } reverse(@pcs); |
|
} |
|
} |
|
} |
|
return @recurseup; |
|
} |
|
|
|
sub recursed_crumbs { |
|
my ($self,$mapurl,$restitle) = @_; |
|
my (@revmapinfo,@revmapres); |
|
my $mapres = $self->getResourceByUrl($mapurl); |
|
if (ref($mapres)) { |
|
@revmapres = map { $self->getByMapPc($_); } split(/,/,$mapres->map_breadcrumbs()); |
|
shift(@revmapres); |
|
} |
|
my $allowedlength = 60; |
|
my $minlength = 5; |
|
my $allowedtitle = 30; |
|
if (($env{'environment.icons'} eq 'iconsonly') && (!$env{'browser.mobile'})) { |
|
$allowedlength = 100; |
|
$allowedtitle = 70; |
|
} |
|
if (length($restitle) > $allowedtitle) { |
|
$restitle = &truncate_crumb_text($restitle,$allowedtitle); |
|
} |
|
my $totallength = length($restitle); |
|
my @links; |
|
|
|
foreach my $map (@revmapres) { |
|
my $pc = $map->map_pc(); |
|
next if ((!$pc) || ($pc == 1)); |
|
push(@links,$map); |
|
my $text = $map->title(); |
|
if ($text eq '') { |
|
$text = '...'; |
|
} |
|
push(@revmapinfo,{'href' => $env{'request.use_absolute'}.$map->link().'?navmap=1','text' => $text,'no_mt' => 1,}); |
|
$totallength += length($text); |
|
} |
|
my $numlinks = scalar(@links); |
|
if ($numlinks) { |
|
if ($totallength - $allowedlength > 0) { |
|
my $available = $allowedlength - length($restitle); |
|
my $avg = POSIX::ceil($available/$numlinks); |
|
if ($avg < $minlength) { |
|
$avg = $minlength; |
|
} |
|
@revmapinfo = (); |
|
foreach my $map (@links) { |
|
my $title = $map->title(); |
|
if ($title eq '') { |
|
$title = '...'; |
|
} |
|
my $showntitle = &truncate_crumb_text($title,$avg); |
|
if ($showntitle ne '') { |
|
push(@revmapinfo,{'href' => $env{'request.use_absolute'}.$map->link().'?navmap=1','text' => $showntitle,'no_mt' => 1,}); |
|
} |
|
} |
|
} |
|
} |
|
if ($restitle ne '') { |
|
push(@revmapinfo,{'text' => $restitle, 'no_mt' => 1}); |
|
} |
|
return @revmapinfo; |
|
} |
|
|
|
sub truncate_crumb_text { |
|
my ($title,$limit) = @_; |
|
my $showntitle = ''; |
|
if (length($title) > $limit) { |
|
my @words = split(/\b\s*/,$title); |
|
if (@words == 1) { |
|
$showntitle = substr($title,0,$limit).' ...'; |
|
} else { |
|
my $linklength = 0; |
|
my $num = 0; |
|
foreach my $word (@words) { |
|
$linklength += 1+length($word); |
|
if ($word eq '-') { |
|
$showntitle =~ s/ $//; |
|
$showntitle .= $word; |
|
} elsif ($linklength > $limit) { |
|
if ($num < @words) { |
|
$showntitle .= $word.' ...'; |
|
last; |
|
} else { |
|
$showntitle .= $word; |
|
} |
|
} else { |
|
$showntitle .= $word.' '; |
|
} |
|
} |
|
$showntitle =~ s/ $//; |
|
} |
|
return $showntitle; |
|
} else { |
|
return $title; |
|
} |
|
} |
|
|
# |
# |
# Determines the open/close dates for printing a map that |
# Determines the open/close dates for printing a map that |
# encloses a resource. |
# encloses a resource. |
Line 2705 sub map_printdates {
|
Line 3039 sub map_printdates {
|
|
|
|
|
|
|
my $opendate = $self->get_mapparam($res->symb(), "$part.printstartdate"); |
my $opendate = $self->get_mapparam($res->symb(),'',"$part.printstartdate"); |
my $closedate= $self->get_mapparam($res->symb(), "$part.printenddate"); |
my $closedate= $self->get_mapparam($res->symb(),'', "$part.printenddate"); |
|
|
|
|
return ($opendate, $closedate); |
return ($opendate, $closedate); |
} |
} |
|
|
sub get_mapparam { |
sub get_mapparam { |
my ($self, $symb, $what) = @_; |
my ($self, $symb, $mapname, $what) = @_; |
|
|
# Ensure the course option hash is populated: |
# Ensure the course option hash is populated: |
|
|
Line 2732 sub get_mapparam {
|
Line 3066 sub get_mapparam {
|
my $uname=$self->{USERNAME}; |
my $uname=$self->{USERNAME}; |
my $udom=$self->{DOMAIN}; |
my $udom=$self->{DOMAIN}; |
|
|
unless ($symb) { return ['']; } |
unless ($symb || $mapname) { return; } |
my $result=''; |
my $result=''; |
|
my ($recursed,@recurseup); |
|
|
# Figure out which map we are in. |
# Figure out which map we are in. |
|
|
my ($mapname,$id,$fn)=&Apache::lonnet::decode_symb($symb); |
if ($symb && !$mapname) { |
$mapname = &Apache::lonnet::deversion($mapname); |
my ($id,$fn); |
|
($mapname,$id,$fn)=&Apache::lonnet::decode_symb($symb); |
|
$mapname = &Apache::lonnet::deversion($mapname); |
|
} |
|
|
my $rwhat=$what; |
my $rwhat=$what; |
$what=~s/^parameter\_//; |
$what=~s/^parameter\_//; |
Line 2772 sub get_mapparam {
|
Line 3108 sub get_mapparam {
|
if (defined($$useropt{$courselevel})) { |
if (defined($$useropt{$courselevel})) { |
return $$useropt{$courselevel}; |
return $$useropt{$courselevel}; |
} |
} |
|
if ($what =~ /\.(encrypturl|hiddenresource)$/) { |
|
unless ($recursed) { |
|
@recurseup = $self->recurseup_maps($mapname); |
|
$recursed = 1; |
|
} |
|
foreach my $item (@recurseup) { |
|
my $norecursechk=$usercourseprefix.'.'.$item.'___(all).'.$what; |
|
if (defined($$useropt{$norecursechk})) { |
|
if ($what =~ /\.(encrypturl|hiddenresource)$/) { |
|
return $$useropt{$norecursechk}; |
|
} |
|
} |
|
} |
|
} |
} |
} |
|
|
# Check course -- group |
# Check course -- group |
Line 2782 sub get_mapparam {
|
Line 3132 sub get_mapparam {
|
if (defined($$courseopt{$grplevel})) { |
if (defined($$courseopt{$grplevel})) { |
return $$courseopt{$grplevel}; |
return $$courseopt{$grplevel}; |
} |
} |
|
if ($what =~ /\.(encrypturl|hiddenresource)$/) { |
|
unless ($recursed) { |
|
@recurseup = $self->recurseup_maps($mapname); |
|
$recursed = 1; |
|
} |
|
foreach my $item (@recurseup) { |
|
my $norecursechk=$usercourseprefix.'.['.$cgroup.'].'.$item.'___(all).'.$what; |
|
if (defined($$courseopt{$norecursechk})) { |
|
if ($what =~ /\.(encrypturl|hiddenresource)$/) { |
|
return $$courseopt{$norecursechk}; |
|
} |
|
} |
|
} |
|
} |
} |
} |
|
|
# Check course -- section |
# Check course -- section |
Line 2794 sub get_mapparam {
|
Line 3158 sub get_mapparam {
|
if (defined($$courseopt{$seclevel})) { |
if (defined($$courseopt{$seclevel})) { |
return $$courseopt{$seclevel}; |
return $$courseopt{$seclevel}; |
} |
} |
|
if ($what =~ /\.(encrypturl|hiddenresource)$/) { |
|
unless ($recursed) { |
|
@recurseup = $self->recurseup_maps($mapname); |
|
$recursed = 1; |
|
} |
|
foreach my $item (@recurseup) { |
|
my $norecursechk=$usercourseprefix.'.['.$csec.'].'.$item.'___(all).'.$what; |
|
if (defined($$courseopt{$norecursechk})) { |
|
if ($what =~ /\.(encrypturl|hiddenresource)$/) { |
|
return $$courseopt{$norecursechk}; |
|
} |
|
} |
|
} |
|
} |
} |
} |
# Check the map parameters themselves: |
# Check the map parameters themselves: |
|
|
my $thisparm = $$parmhash{$symbparm}; |
if ($symb) { |
if (defined($thisparm)) { |
my $symbparm=$symb.'.'.$what; |
return $thisparm; |
my $thisparm = $$parmhash{$symbparm}; |
|
if (defined($thisparm)) { |
|
return $thisparm; |
|
} |
} |
} |
|
|
|
|
Line 2809 sub get_mapparam {
|
Line 3190 sub get_mapparam {
|
if (defined($$courseopt{$courselevel})) { |
if (defined($$courseopt{$courselevel})) { |
return $$courseopt{$courselevel}; |
return $$courseopt{$courselevel}; |
} |
} |
|
if ($what =~ /\.(encrypturl|hiddenresource)$/) { |
|
unless ($recursed) { |
|
@recurseup = $self->recurseup_maps($mapname); |
|
$recursed = 1; |
|
} |
|
foreach my $item (@recurseup) { |
|
my $norecursechk=$usercourseprefix.'.'.$item.'___(all).'.$what; |
|
if (defined($$courseopt{$norecursechk})) { |
|
if ($what =~ /\.(encrypturl|hiddenresource)$/) { |
|
return $$courseopt{$norecursechk}; |
|
} |
|
} |
|
} |
|
} |
} |
} |
return undef; # Unefined if we got here. |
return undef; # Unefined if we got here. |
} |
} |
Line 2864 sub getcourseparam {
|
Line 3259 sub getcourseparam {
|
# |
# |
# We want the course level stuff from the way |
# We want the course level stuff from the way |
# parmval_real operates |
# parmval_real operates |
# TODO: Fator some of this stuff out of |
# TODO: Factor some of this stuff out of |
# both parmval_real and here |
# both parmval_real and here |
# |
# |
my $courselevel = $cid . '.' . $what; |
my $courselevel = $cid . '.' . $what; |
Line 2881 sub getcourseparam {
|
Line 3276 sub getcourseparam {
|
} |
} |
# Try for the group's course level option: |
# Try for the group's course level option: |
|
|
if ($uname ne '' and defined($courseopt)) { |
if ($cgroup ne '' and defined($courseopt)) { |
if (defined($$courseopt{$grplevel})) { |
if (defined($$courseopt{$grplevel})) { |
return $$courseopt{$grplevel}; |
return $$courseopt{$grplevel}; |
} |
} |
Line 2889 sub getcourseparam {
|
Line 3284 sub getcourseparam {
|
|
|
# Try for section level parameters: |
# Try for section level parameters: |
|
|
if ($csec and defined($courseopt)) { |
if ($csec ne '' and defined($courseopt)) { |
if (defined($$courseopt{$seclevel})) { |
if (defined($$courseopt{$seclevel})) { |
return $$courseopt{$seclevel}; |
return $$courseopt{$seclevel}; |
} |
} |
} |
} |
# Try for 'additional' course parameterse: |
# Try for 'additional' course parameters: |
|
|
if (defined($courseopt)) { |
if (defined($courseopt)) { |
if (defined($$courseopt{$courselevel})) { |
if (defined($$courseopt{$courselevel})) { |
Line 2920 resource appears multiple times in the c
|
Line 3315 resource appears multiple times in the c
|
will be returned (useful for maps), unless the multiple parameter has |
will be returned (useful for maps), unless the multiple parameter has |
been included, in which case all instances are returned in an array. |
been included, in which case all instances are returned in an array. |
|
|
=item * B<retrieveResources>(map, filterFunc, recursive, bailout, showall): |
=item * B<retrieveResources>(map, filterFunc, recursive, bailout, showall, noblockcheck): |
|
|
The map is a specification of a map to retreive the resources from, |
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 |
either as a url or as an object. The filterFunc is a reference to a |
Line 2929 true if the resource should be included,
|
Line 3324 true if the resource should be included,
|
be. If recursive is true, the map will be recursively examined, |
be. If recursive is true, the map will be recursively examined, |
otherwise it will not be. If bailout is true, the function will return |
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. If showall is |
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 |
true it will not hide maps that contain nothing but one other map. The |
default, the map is the top-level map of the course, filterFunc is a |
noblockcheck arg is propagated to become the sixth arg in the call to |
function that always returns 1, recursive is true, bailout is false, |
lonnet::allowed when checking a resource's availability during collection |
showall is false. The resources will be returned in a list containing |
of resources using the iterator. noblockcheck needs to be true if |
the resource objects for the corresponding resources, with B<no |
retrieveResources() was called by a routine that itself was called by |
structure information> in the list; regardless of branching, |
lonnet::allowed, in order to avoid recursion. By default the map |
recursion, etc., it will be a flat list. |
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<no structure |
|
information> 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, |
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 |
just a list of all resources. It is also suitable for finding out how |
Line 3002 sub retrieveResources {
|
Line 3402 sub retrieveResources {
|
my $bailout = shift; |
my $bailout = shift; |
if (!defined($bailout)) { $bailout = 0; } |
if (!defined($bailout)) { $bailout = 0; } |
my $showall = shift; |
my $showall = shift; |
|
my $noblockcheck = shift; |
# Create the necessary iterator. |
# Create the necessary iterator. |
if (!ref($map)) { # assume it's a url of a map. |
if (!ref($map)) { # assume it's a url of a map. |
$map = $self->getResourceByUrl($map); |
$map = $self->getResourceByUrl($map); |
Line 3031 sub retrieveResources {
|
Line 3432 sub retrieveResources {
|
# Run down the iterator and collect the resources. |
# Run down the iterator and collect the resources. |
my $curRes; |
my $curRes; |
|
|
while ($curRes = $it->next()) { |
while ($curRes = $it->next(undef,$noblockcheck)) { |
if (ref($curRes)) { |
if (ref($curRes)) { |
if (!&$filterFunc($curRes)) { |
if (!&$filterFunc($curRes)) { |
next; |
next; |
Line 3095 getIterator behaves as follows:
|
Line 3496 getIterator behaves as follows:
|
|
|
=over 4 |
=over 4 |
|
|
=item * B<getIterator>(firstResource, finishResource, filterHash, condition, forceTop, returnTopMap): |
=item * B<getIterator>(firstResource, finishResource, filterHash, condition, forceTop, returnTopMap, $deeplinklisted): |
|
|
All parameters are optional. firstResource is a resource reference |
All parameters are optional. firstResource is a resource reference |
corresponding to where the iterator should start. It defaults to |
corresponding to where the iterator should start. It defaults to |
Line 3112 that is not just a single, 'redirecting'
|
Line 3513 that is not just a single, 'redirecting'
|
will return all information, starting with the top-level map, |
will return all information, starting with the top-level map, |
regardless of content. returnTopMap, if true (default false), will |
regardless of content. returnTopMap, if true (default false), will |
cause the iterator to return the top-level map object (resource 0.0) |
cause the iterator to return the top-level map object (resource 0.0) |
before anything else. |
before anything else. deeplinklisted if true (default false), will |
|
check "listed" status of a resource with a deeplink, and unless "absent" |
|
will exclude deeplink checking when retrieving the browsePriv from |
|
lonnet::allowed(). |
|
|
Thus, by default, only top-level resources will be shown. Change the |
Thus, by default, only top-level resources will be shown. Change the |
condition to a 1 without changing the hash, and all resources will be |
condition to a 1 without changing the hash, and all resources will be |
Line 3182 Note that inside of the loop, it's frequ
|
Line 3586 Note that inside of the loop, it's frequ
|
resource objects will be references, and any non-references will |
resource objects will be references, and any non-references will |
be the tokens described above. |
be the tokens described above. |
|
|
Also note there is some old code floating around that trys to track |
The next() routine can take two (optional) arguments: |
|
closeAllPages - if true will not recurse down a .page |
|
noblockcheck - passed to browsePriv() for passing as sixth arg to |
|
call to lonnet::allowed. This needs to be set if retrieveResources |
|
was already called from another routine called within lonnet::allowed, |
|
so as to prevent recursion. |
|
|
|
Also note there is some old code floating around that tries to track |
the depth of the iterator to see when it's done; do not copy that |
the depth of the iterator to see when it's done; do not copy that |
code. It is difficult to get right and harder to understand than |
code. It is difficult to get right and harder to understand than |
this. They should be migrated to this new style. |
this. They should be migrated to this new style. |
Line 3242 sub new {
|
Line 3653 sub new {
|
# have we done that yet? |
# have we done that yet? |
$self->{HAVE_RETURNED_0} = 0; |
$self->{HAVE_RETURNED_0} = 0; |
|
|
|
# Do we want to check the "listed" status for a resource for which |
|
# deeplinking applies. |
|
$self->{DEEPLINKLISTED} = shift; |
|
|
# Now, we need to pre-process the map, by walking forward and backward |
# Now, we need to pre-process the map, by walking forward and backward |
# over the parts of the map we're going to look at. |
# over the parts of the map we're going to look at. |
|
|
Line 3329 sub new {
|
Line 3744 sub new {
|
if ($resourceCount == 1 && $resource->is_sequence() && !$self->{FORCE_TOP}) { |
if ($resourceCount == 1 && $resource->is_sequence() && !$self->{FORCE_TOP}) { |
my $firstResource = $resource->map_start(); |
my $firstResource = $resource->map_start(); |
my $finishResource = $resource->map_finish(); |
my $finishResource = $resource->map_finish(); |
my $result; |
return Apache::lonnavmaps::iterator->new($self->{NAV_MAP}, $firstResource, |
$result = Apache::lonnavmaps::iterator->new($self->{NAV_MAP}, $firstResource, |
$finishResource, $self->{FILTER}, |
$finishResource, $self->{FILTER}, |
$self->{ALREADY_SEEN}, |
$self->{ALREADY_SEEN}, |
$self->{CONDITION}, |
$self->{CONDITION}, |
$self->{FORCE_TOP}, |
$self->{FORCE_TOP}); |
undef,$self->{DEEPLINKLISTED}); |
return $result; |
|
|
|
|
|
} |
} |
|
|
# Set up some bookkeeping information. |
# Set up some bookkeeping information. |
Line 3362 sub new {
|
Line 3774 sub new {
|
sub next { |
sub next { |
my $self = shift; |
my $self = shift; |
my $closeAllPages=shift; |
my $closeAllPages=shift; |
|
my $noblockcheck = shift; |
if ($self->{FINISHED}) { |
if ($self->{FINISHED}) { |
return END_ITERATOR(); |
return END_ITERATOR(); |
} |
} |
Line 3496 sub next {
|
Line 3909 sub next {
|
# That ends the main iterator logic. Now, do we want to recurse |
# That ends the main iterator logic. Now, do we want to recurse |
# down this map (if this resource is a map)? |
# down this map (if this resource is a map)? |
if ( ($self->{HERE}->is_sequence() || (!$closeAllPages && $self->{HERE}->is_page())) && |
if ( ($self->{HERE}->is_sequence() || (!$closeAllPages && $self->{HERE}->is_page())) && |
(defined($self->{FILTER}->{$self->{HERE}->map_pc()}) xor $self->{CONDITION})) { |
(defined($self->{FILTER}->{$self->{HERE}->map_pc()}) xor $self->{CONDITION}) && |
|
($env{'request.role.adv'} || !$self->{HERE}->randomout())) { |
$self->{RECURSIVE_ITERATOR_FLAG} = 1; |
$self->{RECURSIVE_ITERATOR_FLAG} = 1; |
my $firstResource = $self->{HERE}->map_start(); |
my $firstResource = $self->{HERE}->map_start(); |
my $finishResource = $self->{HERE}->map_finish(); |
my $finishResource = $self->{HERE}->map_finish(); |
Line 3505 sub next {
|
Line 3919 sub next {
|
$finishResource, $self->{FILTER}, |
$finishResource, $self->{FILTER}, |
$self->{ALREADY_SEEN}, |
$self->{ALREADY_SEEN}, |
$self->{CONDITION}, |
$self->{CONDITION}, |
$self->{FORCE_TOP}); |
$self->{FORCE_TOP}, |
|
undef,$self->{DEEPLINKLISTED}); |
} |
} |
|
|
# If this is a blank resource, don't actually return it. |
# If this is a blank resource, don't actually return it. |
# Should you ever find you need it, make sure to add an option to the code |
# Should you ever find you need it, make sure to add an option to the code |
# that you can use; other things depend on this behavior. |
# that you can use; other things depend on this behavior. |
my $browsePriv = $self->{HERE}->browsePriv(); |
my $browsePriv = $self->{HERE}->browsePriv($noblockcheck,$self->{DEEPLINKLISTED}); |
if (!$self->{HERE}->src() || |
if (!$self->{HERE}->src() || |
(!($browsePriv eq 'F') && !($browsePriv eq '2')) ) { |
(!($browsePriv eq 'F') && !($browsePriv eq '2')) ) { |
return $self->next($closeAllPages); |
return $self->next($closeAllPages); |
Line 3843 sub new {
|
Line 4258 sub new {
|
# about this resource in. Not used by the resource object |
# about this resource in. Not used by the resource object |
# directly. |
# directly. |
$self->{DATA} = {}; |
$self->{DATA} = {}; |
|
|
bless($self); |
bless($self); |
|
|
|
# This is a speed optimization, to avoid calling symb() too often. |
|
$self->{SYMB} = $self->symb(); |
|
|
return $self; |
return $self; |
} |
} |
|
|
Line 3936 sub from { my $self=shift; return $self-
|
Line 4354 sub from { my $self=shift; return $self-
|
sub goesto { my $self=shift; return $self->navHash("goesto_", 1); } |
sub goesto { my $self=shift; return $self->navHash("goesto_", 1); } |
sub kind { my $self=shift; return $self->navHash("kind_", 1); } |
sub kind { my $self=shift; return $self->navHash("kind_", 1); } |
sub randomout { my $self=shift; return $self->navHash("randomout_", 1); } |
sub randomout { my $self=shift; return $self->navHash("randomout_", 1); } |
|
sub deeplinkout { my $self=shift; return $self->navHash("deeplinkout_", 1); } |
sub randompick { |
sub randompick { |
my $self = shift; |
my $self = shift; |
my $randompick = $self->parmval('randompick'); |
my $randompick = $self->parmval('randompick'); |
Line 3957 sub src {
|
Line 4376 sub src {
|
} |
} |
sub shown_symb { |
sub shown_symb { |
my $self=shift; |
my $self=shift; |
if ($self->encrypted()) {return &Apache::lonenc::encrypted($self->symb());} |
if ($self->encrypted()) {return &Apache::lonenc::encrypted($self->{SYMB});} |
return $self->symb(); |
return $self->{SYMB}; |
} |
} |
sub id { |
sub id { |
my $self=shift; |
my $self=shift; |
Line 3971 sub enclosing_map_src {
|
Line 4390 sub enclosing_map_src {
|
} |
} |
sub symb { |
sub symb { |
my $self=shift; |
my $self=shift; |
|
if (defined($self->{SYMB})) { return $self->{SYMB}; } |
(my $first, my $second) = $self->{ID} =~ /(\d+).(\d+)/; |
(my $first, my $second) = $self->{ID} =~ /(\d+).(\d+)/; |
my $symbSrc = &Apache::lonnet::declutter($self->src()); |
my $symbSrc = &Apache::lonnet::declutter($self->src()); |
my $symb = &Apache::lonnet::declutter($self->navHash('map_id_'.$first)) |
my $symb = &Apache::lonnet::declutter($self->navHash('map_id_'.$first)) |
Line 3979 sub symb {
|
Line 4399 sub symb {
|
} |
} |
sub wrap_symb { |
sub wrap_symb { |
my $self = shift; |
my $self = shift; |
return $self->{NAV_MAP}->wrap_symb($self->symb()); |
return $self->{NAV_MAP}->wrap_symb($self->{SYMB}); |
} |
} |
sub title { |
sub title { |
my $self=shift; |
my $self=shift; |
Line 4161 sub is_sequence {
|
Line 4581 sub is_sequence {
|
return $self->navHash("is_map_", 1) && |
return $self->navHash("is_map_", 1) && |
$self->navHash("map_type_" . $self->map_pc()) eq 'sequence'; |
$self->navHash("map_type_" . $self->map_pc()) eq 'sequence'; |
} |
} |
|
sub is_missing_map { |
|
my $self=shift; |
|
return $self->navHash("is_map_", 1) && |
|
$self->navHash("map_type_" . $self->map_pc()) eq 'none'; |
|
} |
sub is_survey { |
sub is_survey { |
my $self = shift(); |
my $self = shift(); |
my $part = shift(); |
my $part = shift(); |
Line 4190 sub is_task {
|
Line 4615 sub is_task {
|
|
|
sub is_empty_sequence { |
sub is_empty_sequence { |
my $self=shift; |
my $self=shift; |
my $src = $self->src(); |
|
return !$self->is_page() && $self->navHash("is_map_", 1) && !$self->navHash("map_type_" . $self->map_pc()); |
return !$self->is_page() && $self->navHash("is_map_", 1) && !$self->navHash("map_type_" . $self->map_pc()); |
} |
} |
|
|
Line 4202 sub parmval {
|
Line 4626 sub parmval {
|
if (!defined($part)) { |
if (!defined($part)) { |
$part = '0'; |
$part = '0'; |
} |
} |
return $self->{NAV_MAP}->parmval($part.'.'.$what, $self->symb()); |
return $self->{NAV_MAP}->parmval($part.'.'.$what, $self->{SYMB}); |
} |
} |
|
|
=pod |
=pod |
Line 4235 resource of the map.
|
Line 4659 resource of the map.
|
|
|
Returns a string with the type of the map in it. |
Returns a string with the type of the map in it. |
|
|
=item *B<map_hierarchy>: |
=item * B<map_hierarchy>: |
|
|
Returns a string with a comma-separated ordered list of map_pc IDs |
Returns a string with a comma-separated ordered list of map_pc IDs |
for the hierarchy of maps containing a map, with the top level |
for the hierarchy of maps containing a map, with the top level |
map first, then descending to deeper levels, with the enclosing map last. |
map first, then descending to deeper levels, with the enclosing map last. |
|
|
|
=item * B<map_breadcrumbs>: |
|
|
|
Same as map_hierarchy, except maps containing only a single itemm if |
|
it's a map, or containing no items are omitted, unless it's the top |
|
level map (map_pc = 1), which is always included. |
|
|
=back |
=back |
|
|
=cut |
=cut |
Line 4276 sub map_hierarchy {
|
Line 4706 sub map_hierarchy {
|
my $pc = $self->map_pc(); |
my $pc = $self->map_pc(); |
return $self->navHash("map_hierarchy_$pc", 0); |
return $self->navHash("map_hierarchy_$pc", 0); |
} |
} |
|
sub map_breadcrumbs { |
|
my $self = shift; |
|
my $pc = $self->map_pc(); |
|
return $self->navHash("map_breadcrumbs_$pc", 0); |
|
} |
|
|
##### |
##### |
# Property queries |
# Property queries |
Line 4378 sub printable {
|
Line 4813 sub printable {
|
|
|
my ($self, $part) = @_; |
my ($self, $part) = @_; |
|
|
&Apache::lonnet::logthis($self->symb()); |
|
|
|
|
|
# The following cases apply: |
# The following cases apply: |
# - If a start date is not set, it is replaced by the open date. |
# - If a start date is not set, it is replaced by the open date. |
# - Ditto for start/open replaced by content open. |
# - Ditto for start/open replaced by content open. |
Line 4458 sub awarded {
|
Line 4890 sub awarded {
|
my $self = shift; my $part = shift; |
my $self = shift; my $part = shift; |
$self->{NAV_MAP}->get_user_data(); |
$self->{NAV_MAP}->get_user_data(); |
if (!defined($part)) { $part = '0'; } |
if (!defined($part)) { $part = '0'; } |
return $self->{NAV_MAP}->{STUDENT_DATA}->{$self->symb()}->{'resource.'.$part.'.awarded'}; |
return $self->{NAV_MAP}->{STUDENT_DATA}->{$self->{SYMB}}->{'resource.'.$part.'.awarded'}; |
} |
} |
sub taskversion { |
sub taskversion { |
my $self = shift; my $part = shift; |
my $self = shift; my $part = shift; |
$self->{NAV_MAP}->get_user_data(); |
$self->{NAV_MAP}->get_user_data(); |
if (!defined($part)) { $part = '0'; } |
if (!defined($part)) { $part = '0'; } |
return $self->{NAV_MAP}->{STUDENT_DATA}->{$self->symb()}->{'resource.'.$part.'.version'}; |
return $self->{NAV_MAP}->{STUDENT_DATA}->{$self->{SYMB}}->{'resource.'.$part.'.version'}; |
} |
} |
sub taskstatus { |
sub taskstatus { |
my $self = shift; my $part = shift; |
my $self = shift; my $part = shift; |
$self->{NAV_MAP}->get_user_data(); |
$self->{NAV_MAP}->get_user_data(); |
if (!defined($part)) { $part = '0'; } |
if (!defined($part)) { $part = '0'; } |
return $self->{NAV_MAP}->{STUDENT_DATA}->{$self->symb()}->{'resource.'.$self->taskversion($part).'.'.$part.'.status'}; |
return $self->{NAV_MAP}->{STUDENT_DATA}->{$self->{SYMB}}->{'resource.'.$self->taskversion($part).'.'.$part.'.status'}; |
} |
} |
sub solved { |
sub solved { |
my $self = shift; my $part = shift; |
my $self = shift; my $part = shift; |
$self->{NAV_MAP}->get_user_data(); |
$self->{NAV_MAP}->get_user_data(); |
if (!defined($part)) { $part = '0'; } |
if (!defined($part)) { $part = '0'; } |
return $self->{NAV_MAP}->{STUDENT_DATA}->{$self->symb()}->{'resource.'.$part.'.solved'}; |
return $self->{NAV_MAP}->{STUDENT_DATA}->{$self->{SYMB}}->{'resource.'.$part.'.solved'}; |
} |
} |
sub checkedin { |
sub checkedin { |
my $self = shift; my $part = shift; |
my $self = shift; my $part = shift; |
Line 4484 sub checkedin {
|
Line 4916 sub checkedin {
|
if (!defined($part)) { $part = '0'; } |
if (!defined($part)) { $part = '0'; } |
if ($self->is_task()) { |
if ($self->is_task()) { |
my $version = $self->taskversion($part); |
my $version = $self->taskversion($part); |
return ($self->{NAV_MAP}->{STUDENT_DATA}->{$self->symb()}->{'resource.'.$version .'.'.$part.'.checkedin'},$self->{NAV_MAP}->{STUDENT_DATA}->{$self->symb()}->{'resource.'.$version .'.'.$part.'.checkedin.slot'}); |
return ($self->{NAV_MAP}->{STUDENT_DATA}->{$self->{SYMB}}->{'resource.'.$version .'.'.$part.'.checkedin'},$self->{NAV_MAP}->{STUDENT_DATA}->{$self->{SYMB}}->{'resource.'.$version .'.'.$part.'.checkedin.slot'}); |
} else { |
} else { |
return ($self->{NAV_MAP}->{STUDENT_DATA}->{$self->symb()}->{'resource.'.$part.'.checkedin'},$self->{NAV_MAP}->{STUDENT_DATA}->{$self->symb()}->{'resource.'.$part.'.checkedin.slot'}); |
return ($self->{NAV_MAP}->{STUDENT_DATA}->{$self->{SYMB}}->{'resource.'.$part.'.checkedin'},$self->{NAV_MAP}->{STUDENT_DATA}->{$self->{SYMB}}->{'resource.'.$part.'.checkedin.slot'}); |
} |
} |
} |
} |
# this should work exactly like the copy in lonhomework.pm |
# this should work exactly like the copy in lonhomework.pm |
Line 4503 sub duedate {
|
Line 4935 sub duedate {
|
my $date; |
my $date; |
my @interval=$self->parmval("interval", $part); |
my @interval=$self->parmval("interval", $part); |
my $due_date=$self->parmval("duedate", $part); |
my $due_date=$self->parmval("duedate", $part); |
if ($interval[0] =~ /\d+/) { |
if ($interval[0] =~ /(\d+)/) { |
my $first_access=&Apache::lonnet::get_first_access($interval[1], |
my $timelimit = $1; |
$self->symb); |
my $first_access=&Apache::lonnet::get_first_access($interval[1], |
|
$self->{SYMB}); |
if (defined($first_access)) { |
if (defined($first_access)) { |
my $interval = $first_access+$interval[0]; |
my $interval = $first_access+$timelimit; |
$date = (!$due_date || $interval < $due_date) ? $interval |
$date = (!$due_date || $interval < $due_date) ? $interval |
: $due_date; |
: $due_date; |
} else { |
} else { |
Line 4578 sub weight {
|
Line 5011 sub weight {
|
my $self = shift; my $part = shift; |
my $self = shift; my $part = shift; |
if (!defined($part)) { $part = '0'; } |
if (!defined($part)) { $part = '0'; } |
my $weight = &Apache::lonnet::EXT('resource.'.$part.'.weight', |
my $weight = &Apache::lonnet::EXT('resource.'.$part.'.weight', |
$self->symb(), $self->{DOMAIN}, |
$self->{SYMB}, $self->{DOMAIN}, |
$self->{USERNAME}, |
$self->{USERNAME}, |
$env{'request.course.sec'}); |
$env{'request.course.sec'}); |
return $weight; |
return $weight; |
Line 4587 sub part_display {
|
Line 5020 sub part_display {
|
my $self= shift(); my $partID = shift(); |
my $self= shift(); my $partID = shift(); |
if (! defined($partID)) { $partID = '0'; } |
if (! defined($partID)) { $partID = '0'; } |
my $display=&Apache::lonnet::EXT('resource.'.$partID.'.display', |
my $display=&Apache::lonnet::EXT('resource.'.$partID.'.display', |
$self->symb); |
$self->{SYMB}); |
if (! defined($display) || $display eq '') { |
if (! defined($display) || $display eq '') { |
$display = $partID; |
$display = $partID; |
} |
} |
Line 4601 sub slot_control {
|
Line 5034 sub slot_control {
|
my $available = $self->parmval("available", $part); |
my $available = $self->parmval("available", $part); |
return ($useslots,$availablestudent,$available); |
return ($useslots,$availablestudent,$available); |
} |
} |
|
sub deeplink { |
|
my ($self,$caller,$action) = @_; |
|
my $deeplink = $self->parmval("deeplink"); |
|
if ($deeplink) { |
|
my ($state,$others,$listed,$scope) = split(/,/,$deeplink); |
|
if ($action eq 'getlisted') { |
|
return $listed; |
|
} |
|
if ($env{'request.deeplink.login'}) { |
|
my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; |
|
my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; |
|
my $deeplink_symb = &Apache::loncommon::deeplink_login_symb($cnum,$cdom); |
|
if ($deeplink_symb) { |
|
my ($loginmap,$mapname); |
|
if ($deeplink_symb =~ /\.(page|sequence)$/) { |
|
$mapname = $self->enclosing_map_src(); |
|
$loginmap = &Apache::lonnet::clutter((&Apache::lonnet::decode_symb($deeplink_symb))[2]); |
|
return if ($mapname eq $loginmap); |
|
} else { |
|
return if ($deeplink_symb eq $self->symb()); |
|
if (($scope eq 'map') || ($scope eq 'rec')) { |
|
$mapname = $self->enclosing_map_src(); |
|
$loginmap = &Apache::lonnet::clutter((&Apache::lonnet::decode_symb($deeplink_symb))[0]); |
|
return if ($mapname eq $loginmap); |
|
} |
|
} |
|
if ($scope eq 'rec') { |
|
my $map_pc = $self->navHash('map_pc_'.$mapname); |
|
my @recurseup = split(/,/,$self->navHash('map_hierarchy_'.$map_pc)); |
|
my $login_pc = $self->navHash('map_pc_'.$loginmap); |
|
return if (grep(/^\Q$login_pc\E$/,@recurseup)); |
|
} |
|
} |
|
} |
|
unless (($caller eq 'sequence') || ($state eq 'both')) { |
|
return $listed; |
|
} |
|
} |
|
return; |
|
} |
|
|
# Multiple things need this |
# Multiple things need this |
sub getReturnHash { |
sub getReturnHash { |
my $self = shift; |
my $self = shift; |
|
|
if (!defined($self->{RETURN_HASH})) { |
if (!defined($self->{RETURN_HASH})) { |
my %tmpHash = &Apache::lonnet::restore($self->symb(),undef,$self->{DOMAIN},$self->{USERNAME}); |
my %tmpHash = &Apache::lonnet::restore($self->{SYMB},undef,$self->{DOMAIN},$self->{USERNAME}); |
$self->{RETURN_HASH} = \%tmpHash; |
$self->{RETURN_HASH} = \%tmpHash; |
} |
} |
} |
} |
Line 4672 and use the link as appropriate.
|
Line 5145 and use the link as appropriate.
|
|
|
sub hasDiscussion { |
sub hasDiscussion { |
my $self = shift; |
my $self = shift; |
return $self->{NAV_MAP}->hasDiscussion($self->symb()); |
return $self->{NAV_MAP}->hasDiscussion($self->{SYMB}); |
} |
} |
|
|
sub last_post_time { |
sub last_post_time { |
my $self = shift; |
my $self = shift; |
return $self->{NAV_MAP}->last_post_time($self->symb()); |
return $self->{NAV_MAP}->last_post_time($self->{SYMB}); |
} |
} |
|
|
sub discussion_info { |
sub discussion_info { |
my ($self,$filter) = @_; |
my ($self,$filter) = @_; |
return $self->{NAV_MAP}->discussion_info($self->symb(),$filter); |
return $self->{NAV_MAP}->discussion_info($self->{SYMB},$filter); |
} |
} |
|
|
sub getFeedback { |
sub getFeedback { |
my $self = shift; |
my $self = shift; |
my $source = $self->src(); |
my $source = $self->src(); |
my $symb = $self->symb(); |
my $symb = $self->{SYMB}; |
if ($source =~ /^\/res\//) { $source = substr $source, 5; } |
if ($source =~ /^\/res\//) { $source = substr $source, 5; } |
return $self->{NAV_MAP}->getFeedback($symb,$source); |
return $self->{NAV_MAP}->getFeedback($symb,$source); |
} |
} |
Line 4696 sub getFeedback {
|
Line 5169 sub getFeedback {
|
sub getErrors { |
sub getErrors { |
my $self = shift; |
my $self = shift; |
my $source = $self->src(); |
my $source = $self->src(); |
my $symb = $self->symb(); |
my $symb = $self->{SYMB}; |
if ($source =~ /^\/res\//) { $source = substr $source, 5; } |
if ($source =~ /^\/res\//) { $source = substr $source, 5; } |
return $self->{NAV_MAP}->getErrors($symb,$source); |
return $self->{NAV_MAP}->getErrors($symb,$source); |
} |
} |
Line 4846 sub extractParts {
|
Line 5319 sub extractParts {
|
if ($partorder) { |
if ($partorder) { |
my @parts; |
my @parts; |
for my $part (split (/,/,$partorder)) { |
for my $part (split (/,/,$partorder)) { |
if (!Apache::loncommon::check_if_partid_hidden($part, $self->symb())) { |
if (!Apache::loncommon::check_if_partid_hidden($part, $self->{SYMB})) { |
push @parts, $part; |
push @parts, $part; |
$parts{$part} = 1; |
$parts{$part} = 1; |
} |
} |
Line 4864 sub extractParts {
|
Line 5337 sub extractParts {
|
my $part = $1; |
my $part = $1; |
# This floods the logs if it blows up |
# This floods the logs if it blows up |
if (defined($parts{$part})) { |
if (defined($parts{$part})) { |
&Apache::lonnet::logthis("$part multiply defined in metadata for " . $self->symb()); |
&Apache::lonnet::logthis("$part multiply defined in metadata for " . $self->{SYMB}); |
} |
} |
|
|
# check to see if part is turned off. |
# check to see if part is turned off. |
|
|
if (!Apache::loncommon::check_if_partid_hidden($part, $self->symb())) { |
if (!Apache::loncommon::check_if_partid_hidden($part, $self->{SYMB})) { |
$parts{$part} = 1; |
$parts{$part} = 1; |
} |
} |
} |
} |
} |
} |
my @sortedParts = sort keys %parts; |
my @sortedParts = sort(keys(%parts)); |
$self->{PARTS} = \@sortedParts; |
$self->{PARTS} = \@sortedParts; |
} |
} |
|
|
Line 4895 sub extractParts {
|
Line 5368 sub extractParts {
|
# So we have to use our knowlege of part names to figure out |
# So we have to use our knowlege of part names to figure out |
# where the part names begin and end, and even then, it is possible |
# where the part names begin and end, and even then, it is possible |
# to construct ambiguous situations. |
# to construct ambiguous situations. |
foreach my $data (split /,/, $metadata) { |
foreach my $data (split(/,/, $metadata)) { |
if ($data =~ /^([a-zA-Z]+)response_(.*)/ |
if ($data =~ /^([a-zA-Z]+)response_(.*)/ |
|| $data =~ /^(Task)_(.*)/) { |
|| $data =~ /^(Task)_(.*)/) { |
my $responseType = $1; |
my $responseType = $1; |
my $partStuff = $2; |
my $partStuff = $2; |
my $partIdSoFar = ''; |
my $partIdSoFar = ''; |
my @partChunks = split /_/, $partStuff; |
my @partChunks = split(/_/, $partStuff); |
my $i = 0; |
my $i = 0; |
for ($i = 0; $i < scalar(@partChunks); $i++) { |
for ($i = 0; $i < scalar(@partChunks); $i++) { |
if ($partIdSoFar) { $partIdSoFar .= '_'; } |
if ($partIdSoFar) { $partIdSoFar .= '_'; } |
Line 5374 sub status {
|
Line 5847 sub status {
|
sub check_for_slot { |
sub check_for_slot { |
my $self = shift; |
my $self = shift; |
my $part = shift; |
my $part = shift; |
my $symb = $self->symb(); |
my $symb = $self->{SYMB}; |
my ($use_slots,$available,$availablestudent) = $self->slot_control($part); |
my ($use_slots,$available,$availablestudent) = $self->slot_control($part); |
if (($use_slots ne '') && ($use_slots !~ /^\s*no\s*$/i)) { |
if (($use_slots ne '') && ($use_slots !~ /^\s*no\s*$/i)) { |
my @slots = (split(/:/,$availablestudent),split(/:/,$available)); |
my @slots = (split(/:/,$availablestudent),split(/:/,$available)); |
Line 5383 sub check_for_slot {
|
Line 5856 sub check_for_slot {
|
my $cnum=$env{'course.'.$cid.'.num'}; |
my $cnum=$env{'course.'.$cid.'.num'}; |
my $now = time; |
my $now = time; |
my $num_usable_slots = 0; |
my $num_usable_slots = 0; |
|
my ($checkedin,$checkedinslot,%consumed_uniq,%slots); |
if (@slots > 0) { |
if (@slots > 0) { |
my %slots=&Apache::lonnet::get('slots',[@slots],$cdom,$cnum); |
%slots=&Apache::lonnet::get('slots',[@slots],$cdom,$cnum); |
if (&Apache::lonnet::error(%slots)) { |
if (&Apache::lonnet::error(%slots)) { |
return (UNKNOWN); |
return (UNKNOWN); |
} |
} |
my @sorted_slots = &Apache::loncommon::sorted_slots(\@slots,\%slots,'starttime'); |
my @sorted_slots = &Apache::loncommon::sorted_slots(\@slots,\%slots,'starttime'); |
my ($checkedin,$checkedinslot); |
|
foreach my $slot_name (@sorted_slots) { |
foreach my $slot_name (@sorted_slots) { |
next if (!defined($slots{$slot_name}) || !ref($slots{$slot_name})); |
next if (!defined($slots{$slot_name}) || !ref($slots{$slot_name})); |
my $end = $slots{$slot_name}->{'endtime'}; |
my $end = $slots{$slot_name}->{'endtime'}; |
Line 5402 sub check_for_slot {
|
Line 5875 sub check_for_slot {
|
} else { |
} else { |
if ($ip ne '') { |
if ($ip ne '') { |
if (!&Apache::loncommon::check_ip_acc($ip)) { |
if (!&Apache::loncommon::check_ip_acc($ip)) { |
return (RESERVED_LOCATION,$ip,$slot_name); |
return (RESERVED_LOCATION,$end,$slot_name); |
} |
} |
} |
} |
my @proctors; |
my @proctors; |
Line 5413 sub check_for_slot {
|
Line 5886 sub check_for_slot {
|
($checkedin,$checkedinslot) = $self->checkedin(); |
($checkedin,$checkedinslot) = $self->checkedin(); |
unless ((grep(/^\Q$checkedin\E/,@proctors)) && |
unless ((grep(/^\Q$checkedin\E/,@proctors)) && |
($checkedinslot eq $slot_name)) { |
($checkedinslot eq $slot_name)) { |
return (NEEDS_CHECKIN,undef,$slot_name); |
return (NEEDS_CHECKIN,$end,$slot_name); |
} |
} |
} |
} |
return (RESERVED,$end,$slot_name); |
return (RESERVED,$end,$slot_name); |
Line 5423 sub check_for_slot {
|
Line 5896 sub check_for_slot {
|
$num_usable_slots ++; |
$num_usable_slots ++; |
} |
} |
} |
} |
my ($is_correct,$got_grade); |
my ($is_correct,$wait_for_grade); |
if ($self->is_task()) { |
if ($self->is_task()) { |
my $taskstatus = $self->taskstatus(); |
my $taskstatus = $self->taskstatus(); |
$is_correct = (($taskstatus eq 'pass') || |
$is_correct = (($taskstatus eq 'pass') || |
($self->solved() =~ /^correct_/)); |
($self->solved() =~ /^correct_/)); |
$got_grade = ($taskstatus =~ /^(?:pass|fail)$/); |
unless ($taskstatus =~ /^(?:pass|fail)$/) { |
|
$wait_for_grade = 1; |
|
} |
} else { |
} else { |
$got_grade = 1; |
unless ($self->completable()) { |
$is_correct = ($self->solved() =~ /^correct_/); |
$wait_for_grade = 1; |
|
} |
|
unless (($self->problemstatus($part) eq 'no') || |
|
($self->problemstatus($part) eq 'no_feedback_ever')) { |
|
$is_correct = ($self->solved($part) =~ /^correct_/); |
|
$wait_for_grade = 0; |
|
} |
} |
} |
($checkedin,$checkedinslot) = $self->checkedin(); |
($checkedin,$checkedinslot) = $self->checkedin(); |
if ($checkedin) { |
if ($checkedin) { |
if (!$got_grade) { |
if (ref($slots{$checkedinslot}) eq 'HASH') { |
|
$consumed_uniq{$checkedinslot} = $slots{$checkedinslot}{'uniqueperiod'}; |
|
} |
|
if ($wait_for_grade) { |
return (WAITING_FOR_GRADE); |
return (WAITING_FOR_GRADE); |
} elsif ($is_correct) { |
} elsif ($is_correct) { |
return (CORRECT); |
return (CORRECT); |
Line 5450 sub check_for_slot {
|
Line 5934 sub check_for_slot {
|
if (ref($reservable) eq 'HASH') { |
if (ref($reservable) eq 'HASH') { |
if ((ref($reservable->{'now_order'}) eq 'ARRAY') && (ref($reservable->{'now'}) eq 'HASH')) { |
if ((ref($reservable->{'now_order'}) eq 'ARRAY') && (ref($reservable->{'now'}) eq 'HASH')) { |
foreach my $slot (reverse (@{$reservable->{'now_order'}})) { |
foreach my $slot (reverse (@{$reservable->{'now_order'}})) { |
|
my $canuse; |
if (($reservable->{'now'}{$slot}{'symb'} eq '') || |
if (($reservable->{'now'}{$slot}{'symb'} eq '') || |
($reservable->{'now'}{$slot}{'symb'} eq $symb)) { |
($reservable->{'now'}{$slot}{'symb'} eq $symb)) { |
|
$canuse = 1; |
|
} |
|
if ($canuse) { |
|
if ($checkedin) { |
|
if (ref($consumed_uniq{$checkedinslot}) eq 'ARRAY') { |
|
my ($uniqstart,$uniqend)=@{$consumed_uniq{$checkedinslot}}; |
|
if ($reservable->{'now'}{$slot}{'uniqueperiod'} =~ /^(\d+),(\d+)$/) { |
|
my ($new_uniq_start,$new_uniq_end) = ($1,$2); |
|
next if (! |
|
($uniqstart < $new_uniq_start && $uniqend < $new_uniq_start) || |
|
($uniqstart > $new_uniq_end && $uniqend > $new_uniq_end )); |
|
} |
|
} |
|
} |
return(RESERVABLE,$reservable->{'now'}{$slot}{'endreserve'}); |
return(RESERVABLE,$reservable->{'now'}{$slot}{'endreserve'}); |
} |
} |
} |
} |
} |
} |
if ((ref($reservable->{'future_order'}) eq 'ARRAY') && (ref($reservable->{'future'}) eq 'HASH')) { |
if ((ref($reservable->{'future_order'}) eq 'ARRAY') && (ref($reservable->{'future'}) eq 'HASH')) { |
foreach my $slot (@{$reservable->{'future_order'}}) { |
foreach my $slot (@{$reservable->{'future_order'}}) { |
|
my $canuse; |
if (($reservable->{'future'}{$slot}{'symb'} eq '') || |
if (($reservable->{'future'}{$slot}{'symb'} eq '') || |
($reservable->{'future'}{$slot}{'symb'} eq $symb)) { |
($reservable->{'future'}{$slot}{'symb'} eq $symb)) { |
|
$canuse = 1; |
|
} |
|
if ($canuse) { |
|
if ($checkedin) { |
|
if (ref($consumed_uniq{$checkedinslot}) eq 'ARRAY') { |
|
my ($uniqstart,$uniqend)=@{$consumed_uniq{$checkedinslot}}; |
|
if ($reservable->{'future'}{$slot}{'uniqueperiod'} =~ /^(\d+),(\d+)$/) { |
|
my ($new_uniq_start,$new_uniq_end) = ($1,$2); |
|
next if (! |
|
($uniqstart < $new_uniq_start && $uniqend < $new_uniq_start) || |
|
($uniqstart > $new_uniq_end && $uniqend > $new_uniq_end )); |
|
} |
|
} |
|
} |
return(RESERVABLE_LATER,$reservable->{'future'}{$slot}{'startreserve'}); |
return(RESERVABLE_LATER,$reservable->{'future'}{$slot}{'startreserve'}); |
} |
} |
} |
} |
Line 5610 sub completable {
|
Line 6124 sub completable {
|
|
|
=pod |
=pod |
|
|
|
B<Answerable> |
|
|
|
The answerable method differs from the completable method in its handling of problem parts |
|
for which feedback on correctness is suppressed, but the student still has tries left, and |
|
the problem part is not past due, (i.e., the student could submit a different answer if |
|
he/she so chose). For that case completable will return 0, whereas answerable will return 1. |
|
|
|
=cut |
|
|
|
sub answerable { |
|
my $self = shift; |
|
if (!$self->is_problem()) { return 0; } |
|
my $partCount = $self->countParts(); |
|
foreach my $part (@{$self->parts()}) { |
|
if ($part eq '0' && $partCount != 1) { next; } |
|
my $status = $self->status($part); |
|
if ($self->getCompletionStatus($part) == ATTEMPTED() || |
|
$self->getCompletionStatus($part) == CREDIT_ATTEMPTED() || |
|
$status == ANSWER_SUBMITTED() ) { |
|
if ($self->tries($part) < $self->maxtries($part) || !$self->maxtries($part)) { |
|
return 1; |
|
} |
|
} |
|
if ($status == OPEN() || $status == TRIES_LEFT() || $status == NETWORK_FAILURE()) { |
|
return 1; |
|
} |
|
} |
|
# None of the parts were answerable, so neither is this problem. |
|
return 0; |
|
} |
|
|
|
=pod |
|
|
=head2 Resource/Nav Map Navigation |
=head2 Resource/Nav Map Navigation |
|
|
=over 4 |
=over 4 |
Line 5645 sub getPrevious {
|
Line 6192 sub getPrevious {
|
my $self = shift; |
my $self = shift; |
my @branches; |
my @branches; |
my $from = $self->from(); |
my $from = $self->from(); |
foreach my $branch ( split /,/, $from) { |
foreach my $branch ( split(/,/, $from)) { |
my $choice = $self->{NAV_MAP}->getById($branch); |
my $choice = $self->{NAV_MAP}->getById($branch); |
my $prev = $choice->comesfrom(); |
my $prev = $choice->comesfrom(); |
$prev = $self->{NAV_MAP}->getById($prev); |
$prev = $self->{NAV_MAP}->getById($prev); |
Line 5657 sub getPrevious {
|
Line 6204 sub getPrevious {
|
|
|
sub browsePriv { |
sub browsePriv { |
my $self = shift; |
my $self = shift; |
|
my $noblockcheck = shift; |
|
my $deeplinklisted = shift; |
if (defined($self->{BROWSE_PRIV})) { |
if (defined($self->{BROWSE_PRIV})) { |
return $self->{BROWSE_PRIV}; |
return $self->{BROWSE_PRIV}; |
} |
} |
|
my ($nodeeplinkcheck,$nodeeplinkout); |
|
if ($deeplinklisted) { |
|
my $deeplink = $self->deeplink(undef,'getlisted'); |
|
if (($deeplink) && ($deeplink ne 'absent')) { |
|
$nodeeplinkcheck = 1; |
|
} |
|
$nodeeplinkout = 1; |
|
} |
$self->{BROWSE_PRIV} = &Apache::lonnet::allowed('bre',$self->src(), |
$self->{BROWSE_PRIV} = &Apache::lonnet::allowed('bre',$self->src(), |
$self->symb()); |
$self->{SYMB},undef, |
|
undef,$noblockcheck, |
|
undef,$nodeeplinkcheck, |
|
$nodeeplinkout); |
} |
} |
|
|
=pod |
=pod |