version 1.387, 2006/06/05 17:55:59
|
version 1.402, 2007/10/05 18:48:20
|
Line 31 package Apache::lonnavmaps;
|
Line 31 package Apache::lonnavmaps;
|
|
|
use strict; |
use strict; |
use GDBM_File; |
use GDBM_File; |
use Apache::Constants qw(:common :http); |
|
use Apache::loncommon(); |
use Apache::loncommon(); |
use Apache::lonmenu(); |
|
use Apache::lonenc(); |
use Apache::lonenc(); |
use Apache::lonlocal; |
use Apache::lonlocal; |
use Apache::lonnet; |
use Apache::lonnet; |
use POSIX qw (floor strftime); |
use POSIX qw (floor strftime); |
use Data::Dumper; # for debugging, not always |
use Data::Dumper; # for debugging, not always |
use Time::HiRes qw( gettimeofday tv_interval ); |
use Time::HiRes qw( gettimeofday tv_interval ); |
use lib '/home/httpd/lib/perl/'; |
|
use LONCAPA; |
use LONCAPA; |
|
|
# symbolic constants |
# symbolic constants |
Line 88 my %colormap =
|
Line 85 my %colormap =
|
$resObj->PARTIALLY_CORRECT => '#006600' |
$resObj->PARTIALLY_CORRECT => '#006600' |
); |
); |
# And a special case in the nav map; what to do when the assignment |
# And a special case in the nav map; what to do when the assignment |
# is not yet done and due in less then 24 hours |
# is not yet done and due in less than 24 hours |
my $hurryUpColor = "#FF0000"; |
my $hurryUpColor = "#FF0000"; |
|
|
sub launch_win { |
|
my ($mode,$script,$toplinkitems,$firsttime)=@_; |
|
my $result; |
|
if ($script ne 'no') { |
|
$result.='<script type="text/javascript">'; |
|
} |
|
if ($firsttime) { |
|
$result.='function launch_navmapwin() { |
|
newWindow=open(\'/adm/navmaps?launchExternalRoles\',\'loncapanav\',\'width=400,height=600,scrollbars=1\'); |
|
}'; |
|
} else { |
|
$result.='function launch_navmapwin() { |
|
newWindow=open(\'/adm/navmaps?launchExternal\',\'loncapanav\',\'width=400,height=600,scrollbars=1\'); |
|
}'; |
|
} |
|
if ($mode eq 'now') { |
|
$result.="\nlaunch_navmapwin();\n"; |
|
} |
|
if ($script ne 'no') { |
|
$result.='</script>'; |
|
} |
|
if ($mode eq 'link') { |
|
&add_linkitem($toplinkitems,'launchnav','launch_navmapwin()', |
|
"Launch navigation window"); |
|
} |
|
return $result; |
|
} |
|
|
|
sub close { |
sub close { |
if ($env{'environment.remotenavmap'} ne 'on') { return ''; } |
if ($env{'environment.remotenavmap'} ne 'on') { return ''; } |
return(<<ENDCLOSE); |
return(<<ENDCLOSE); |
Line 147 this.document.navform.submit();
|
Line 116 this.document.navform.submit();
|
ENDUPDATE |
ENDUPDATE |
} |
} |
|
|
sub handler { |
|
my $r = shift; |
|
real_handler($r); |
|
} |
|
|
|
sub real_handler { |
|
my $r = shift; |
|
#my $t0=[&gettimeofday()]; |
|
# Handle header-only request |
|
if ($r->header_only) { |
|
if ($env{'browser.mathml'}) { |
|
&Apache::loncommon::content_type($r,'text/xml'); |
|
} else { |
|
&Apache::loncommon::content_type($r,'text/html'); |
|
} |
|
$r->send_http_header; |
|
return OK; |
|
} |
|
|
|
# Send header, don't cache this page |
|
if ($env{'browser.mathml'}) { |
|
&Apache::loncommon::content_type($r,'text/xml'); |
|
} else { |
|
&Apache::loncommon::content_type($r,'text/html'); |
|
} |
|
&Apache::loncommon::no_cache($r); |
|
|
|
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'); |
|
my $menu=&Apache::lonmenu::reopenmenu(); |
|
my $navstatus=&Apache::lonmenu::get_nav_status(); |
|
if ($menu) { |
|
$menu=(<<MENU) |
|
swmenu=$menu |
|
swmenu.clearTimeout(swmenu.menucltim); |
|
$navstatus |
|
MENU |
|
} else { |
|
my $nothing = &Apache::lonhtmlcommon::javascript_nothing(); |
|
my $mainwindow='window.open('.$nothing.',"loncapaclient","",false);'; |
|
$menu=(<<MENU) |
|
swmenu=$mainwindow |
|
$navstatus |
|
MENU |
|
} |
|
$r->send_http_header; |
|
my $js =<<"ENDSUBM"; |
|
<script type="text/javascript"> |
|
function submitthis() { |
|
$menu |
|
self.close(); |
|
} |
|
|
|
</script> |
|
ENDSUBM |
|
$r->print(&Apache::loncommon::start_page(undef,$js, |
|
{'only_body' => 1, |
|
'bgcolor' => '#FFFFFF', |
|
'add_entries' => |
|
{'onload' => |
|
"submitthis()"}}). |
|
&Apache::loncommon::end_page()); |
|
|
|
return OK; |
|
} |
|
if ($ENV{QUERY_STRING} =~ /^launchExternal/) { |
|
&Apache::lonnet::put('environment',{'remotenavmap' => 'on'}); |
|
&Apache::lonnet::appenv('environment.remotenavmap' => 'on'); |
|
my $menu=&Apache::lonmenu::reopenmenu(); |
|
my $navstatus=&Apache::lonmenu::get_nav_status(); |
|
if ($menu) { |
|
$r->print(<<MENU); |
|
<script type="text/javascript"> |
|
swmenu=$menu |
|
swmenu.clearTimeout(swmenu.menucltim); |
|
$navstatus |
|
</script> |
|
MENU |
|
} |
|
} |
|
if ($ENV{QUERY_STRING} eq 'turningOffExternal') { |
|
$env{'environment.remotenavmap'}='off'; |
|
} |
|
|
|
# Create the nav map |
|
my $navmap = Apache::lonnavmaps::navmap->new(); |
|
|
|
if (!defined($navmap)) { |
|
my $requrl = $r->uri; |
|
$env{'user.error.msg'} = "$requrl:bre:0:0:Course not initialized"; |
|
return HTTP_NOT_ACCEPTABLE; |
|
} |
|
$r->send_http_header; |
|
|
|
# ------------------------------------------------------------ Get query string |
|
&Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['register','sort','showOnlyHomework','postsymb']); |
|
|
|
# ----------------------------------------------------- Force menu registration |
|
my $body_only=''; |
|
my $js; |
|
if ($env{'environment.remotenavmap'} eq 'on') { |
|
$js='<script type="text/javascript"> |
|
function collapse() { |
|
this.document.location="/adm/navmaps?collapseExternal"; |
|
} |
|
</script>'; |
|
$body_only=1; |
|
} |
|
|
|
# Header |
|
my $course_type = &Apache::loncommon::course_type(); |
|
$r->print(&Apache::loncommon::start_page('Navigate '.$course_type. |
|
' Contents', |
|
$js, |
|
{'only_body' => $body_only, |
|
'force_register' => |
|
$env{'form.register'},})); |
|
$r->print('<script type="text/javascript">window.focus();</script>'); |
|
|
|
$r->rflush(); |
|
|
|
# Check that it's defined |
|
if (!($navmap->courseMapDefined())) { |
|
$r->print(&Apache::loncommon::help_open_menu('','Navigation Screen','Navigation_Screen','',undef,'RAT')); |
|
$r->print('<font size="+2" color="red">'.&mt('Coursemap undefined.'). |
|
'</font>' . |
|
&Apache::loncommon::end_page()); |
|
return OK; |
|
} |
|
|
|
# See if there's only one map in the top-level, if we don't |
|
# already have a filter... if so, automatically display it |
|
# (older code; should use retrieveResources) |
|
if ($ENV{QUERY_STRING} !~ /filter/) { |
|
my $iterator = $navmap->getIterator(undef, undef, undef, 0); |
|
my $curRes; |
|
my $sequenceCount = 0; |
|
my $sequenceId; |
|
while ($curRes = $iterator->next()) { |
|
if (ref($curRes) && $curRes->is_sequence()) { |
|
$sequenceCount++; |
|
$sequenceId = $curRes->map_pc(); |
|
} |
|
} |
|
|
|
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 |
|
# is a fresh call. |
|
$env{'form.filter'} = "$sequenceId"; |
|
} |
|
} |
|
|
|
if ($ENV{QUERY_STRING} eq 'launchExternal') { |
|
$r->print(' |
|
<form name="returnwin" action="/adm/flip?postdata=navlaunch%3a" |
|
method="post" target="loncapaclient"> |
|
</form>'); |
|
$r->print(' |
|
<script type="text/javascript"> |
|
this.document.returnwin.submit(); |
|
</script>'); |
|
} |
|
|
|
if ($env{'environment.remotenavmap'} ne 'on') { |
|
$r->print(&launch_win('link','yes',\%toplinkitems)); |
|
} |
|
if ($env{'environment.remotenavmap'} eq 'on') { |
|
&add_linkitem(\%toplinkitems,'closenav','collapse()', |
|
"Close navigation window"); |
|
} |
|
|
|
|
|
# Check to see if the student is jumping to next open, do-able problem |
|
if ($ENV{QUERY_STRING} =~ /^jumpToFirstHomework/) { |
|
# Find the next homework problem that they can do. |
|
my $iterator = $navmap->getIterator(undef, undef, undef, 1); |
|
my $curRes; |
|
my $foundDoableProblem = 0; |
|
my $minimumduedate; |
|
|
|
while ($curRes = $iterator->next()) { |
|
if (ref($curRes) && $curRes->is_problem()) { |
|
my $status = $curRes->status(); |
|
if ($curRes->completable()) { |
|
my $thisduedate=$curRes->duedate(); |
|
unless ($foundDoableProblem) { |
|
$minimumduedate=$thisduedate; |
|
} |
|
|
|
$foundDoableProblem = 1; |
|
|
|
if ($thisduedate<=$minimumduedate) { |
|
# Pop open all previous maps |
|
my $stack = $iterator->getStack(); |
|
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); |
|
|
|
# Mark as both "here" and "jump" |
|
$env{'form.postsymb'} = $curRes->symb(); |
|
$minimumduedate=$thisduedate; |
|
} |
|
} |
|
} |
|
} |
|
|
|
# If we found no problems, print a note to that effect. |
|
if (!$foundDoableProblem) { |
|
$r->print("<font size='+2'>All homework assignments have been completed.</font><br /><br />"); |
|
} |
|
} else { |
|
&add_linkitem(\%toplinkitems,'firsthomework', |
|
'location.href="navmaps?jumpToFirstHomework"', |
|
"Show my first due problem"); |
|
} |
|
|
|
my $suppressEmptySequences = 0; |
|
my $filterFunc = undef; |
|
my $resource_no_folder_link = 0; |
|
|
|
# Display only due homework. |
|
my $showOnlyHomework = 0; |
|
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'}.'"', |
|
"Show everything"); |
|
$r->print("<p><font size='+2'>".&mt("Uncompleted Problems")."</font></p>"); |
|
$env{'form.filter'} = ''; |
|
$env{'form.condition'} = 1; |
|
$resource_no_folder_link = 1; |
|
} else { |
|
&add_linkitem(\%toplinkitems,'uncompleted', |
|
'location.href="navmaps?sort='.$env{'form.sort'}. |
|
'&showOnlyHomework=1"', |
|
"Show only uncompleted problems"); |
|
} |
|
|
|
my %selected=($env{'form.sort'} => 'selected=on'); |
|
my $sort_html=("<form> |
|
<nobr> |
|
<input type=\"hidden\" name=\"showOnlyHomework\" value=\"".$env{'form.showOnlyHomework'}."\" /> |
|
<input type=\"submit\" value=\"".&mt('Sort by:')."\" /> |
|
<select name=\"sort\"> |
|
<option value=\"default\" $selected{'default'}>".&mt('Default')."</option> |
|
<option value=\"title\" $selected{'title'} >".&mt('Title')."</option> |
|
<option value=\"duedate\" $selected{'duedate'}>".&mt('Duedate')."</option> |
|
<option value=\"discussion\" $selected{'discussion'}>".&mt('Has New Discussion')."</option> |
|
</select> |
|
</nobr> |
|
</form>"); |
|
# renderer call |
|
my $renderArgs = { 'cols' => [0,1,2,3], |
|
'sort' => $env{'form.sort'}, |
|
'url' => '/adm/navmaps', |
|
'navmap' => $navmap, |
|
'suppressNavmap' => 1, |
|
'suppressEmptySequences' => $suppressEmptySequences, |
|
'filterFunc' => $filterFunc, |
|
'resource_no_folder_link' => $resource_no_folder_link, |
|
'sort_html'=> $sort_html, |
|
'r' => $r, |
|
'caller' => 'navmapsdisplay', |
|
'linkitems' => \%toplinkitems}; |
|
my $render = render($renderArgs); |
|
|
|
# If no resources were printed, print a reassuring message so the |
|
# user knows there was no error. |
|
if ($renderArgs->{'counter'} == 0) { |
|
if ($showOnlyHomework) { |
|
$r->print("<p><font size='+1'>".&mt("All homework is currently completed").".</font></p>"); |
|
} else { # both jumpToFirstHomework and normal use the same: course must be empty |
|
$r->print("<p><font size='+1'>This course is empty.</font></p>"); |
|
} |
|
} |
|
#my $td=&tv_interval($t0); |
|
#$r->print("<br />$td"); |
|
|
|
$r->print(&Apache::loncommon::end_page()); |
|
$r->rflush(); |
|
|
|
return OK; |
|
} |
|
|
|
# Convenience functions: Returns a string that adds or subtracts |
# Convenience functions: Returns a string that adds or subtracts |
# the second argument from the first hash, appropriate for the |
# the second argument from the first hash, appropriate for the |
# query string that determines which folders to recurse on |
# query string that determines which folders to recurse on |
Line 473 sub getLinkForResource {
|
Line 148 sub getLinkForResource {
|
if (defined($res)) { |
if (defined($res)) { |
my $anchor; |
my $anchor; |
if ($res->is_page()) { |
if ($res->is_page()) { |
foreach (@$stack) { if (defined($_)) { $anchor = $_; } } |
foreach my $item (@$stack) { if (defined($item)) { $anchor = $item; } } |
$anchor=&escape($anchor->shown_symb()); |
$anchor=&escape($anchor->shown_symb()); |
return ($res->link(),$res->shown_symb(),$anchor); |
return ($res->link(),$res->shown_symb(),$anchor); |
} |
} |
Line 491 sub getLinkForResource {
|
Line 166 sub getLinkForResource {
|
# (when we first recurse on a map, it puts an undefined resource |
# (when we first recurse on a map, it puts an undefined resource |
# on the bottom because $self->{HERE} isn't defined yet, and we |
# on the bottom because $self->{HERE} isn't defined yet, and we |
# want the src for the map anyhow) |
# want the src for the map anyhow) |
foreach (@$stack) { |
foreach my $item (@$stack) { |
if (defined($_)) { $res = $_; } |
if (defined($item)) { $res = $item; } |
} |
} |
|
|
return ($res->link(),$res->shown_symb()); |
if ($res) { |
|
return ($res->link(),$res->shown_symb()); |
|
} |
|
return; |
} |
} |
|
|
# Convenience function: This separates the logic of how to create |
# Convenience function: This separates the logic of how to create |
Line 520 sub getDescription {
|
Line 198 sub getDescription {
|
} |
} |
if ($status == $res->OPEN) { |
if ($status == $res->OPEN) { |
if ($res->duedate($part)) { |
if ($res->duedate($part)) { |
return &mt("Due")." " .timeToHumanString($res->duedate($part),'end'); |
if ($res->is_practice()) { |
|
return &mt("Closes ")." " .timeToHumanString($res->duedate($part),'start'); |
|
} else { |
|
return &mt("Due")." " .timeToHumanString($res->duedate($part),'end'); |
|
} |
} else { |
} else { |
return &mt("Open, no due date"); |
return &mt("Open, no due date"); |
} |
} |
Line 529 sub getDescription {
|
Line 211 sub getDescription {
|
return &mt("Answer open")." " . timeToHumanString($res->answerdate($part),'start'); |
return &mt("Answer open")." " . timeToHumanString($res->answerdate($part),'start'); |
} |
} |
if ($status == $res->PAST_DUE_NO_ANSWER) { |
if ($status == $res->PAST_DUE_NO_ANSWER) { |
return &mt("Was due")." " . timeToHumanString($res->duedate($part),'end'); |
if ($res->is_practice()) { |
|
return &mt("Closed")." " . timeToHumanString($res->duedate($part),'start'); |
|
} else { |
|
return &mt("Was due")." " . timeToHumanString($res->duedate($part),'end'); |
|
} |
} |
} |
if (($status == $res->ANSWER_OPEN || $status == $res->PARTIALLY_CORRECT) |
if (($status == $res->ANSWER_OPEN || $status == $res->PARTIALLY_CORRECT) |
&& $res->handgrade($part) ne 'yes') { |
&& $res->handgrade($part) ne 'yes') { |
Line 563 sub getDescription {
|
Line 249 sub getDescription {
|
} |
} |
} |
} |
|
|
# Convenience function, so others can use it: Is the problem due in less then |
# Convenience function, so others can use it: Is the problem due in less than |
# 24 hours, and still can be done? |
# 24 hours, and still can be done? |
|
|
sub dueInLessThan24Hours { |
sub dueInLessThan24Hours { |
Line 578 sub dueInLessThan24Hours {
|
Line 264 sub dueInLessThan24Hours {
|
} |
} |
|
|
# Convenience function, so others can use it: Is there only one try remaining for the |
# Convenience function, so others can use it: Is there only one try remaining for the |
# part, with more then one try to begin with, not due yet and still can be done? |
# part, with more than one try to begin with, not due yet and still can be done? |
sub lastTry { |
sub lastTry { |
my $res = shift; |
my $res = shift; |
my $part = shift; |
my $part = shift; |
Line 647 sub timeToHumanString {
|
Line 333 sub timeToHumanString {
|
my $tense = $inPast ? " ago" : ""; |
my $tense = $inPast ? " ago" : ""; |
my $prefix = $inPast ? "" : "in "; |
my $prefix = $inPast ? "" : "in "; |
|
|
# Less then a minute |
# Less than a minute |
if ( $delta < $minute ) { |
if ( $delta < $minute ) { |
if ($delta == 1) { return "${prefix}1 second$tense"; } |
if ($delta == 1) { return "${prefix}1 second$tense"; } |
return "$prefix$delta seconds$tense"; |
return "$prefix$delta seconds$tense"; |
} |
} |
|
|
# Less then an hour |
# Less than an hour |
if ( $delta < $hour ) { |
if ( $delta < $hour ) { |
# If so, use minutes |
# If so, use minutes |
my $minutes = floor($delta / 60); |
my $minutes = floor($delta / 60); |
Line 661 sub timeToHumanString {
|
Line 347 sub timeToHumanString {
|
return "$prefix$minutes minutes$tense"; |
return "$prefix$minutes minutes$tense"; |
} |
} |
|
|
# Is it less then 24 hours away? If so, |
# Is it less than 24 hours away? If so, |
# display hours + minutes |
# display hours + minutes |
if ( $delta < $hour * 24) { |
if ( $delta < $hour * 24) { |
my $hours = floor($delta / $hour); |
my $hours = floor($delta / $hour); |
Line 687 sub timeToHumanString {
|
Line 373 sub timeToHumanString {
|
return $timeStr.&Apache::lonlocal::gettimezone($time); |
return $timeStr.&Apache::lonlocal::gettimezone($time); |
} |
} |
|
|
# Less then 5 days away, display day of the week and |
# Less than 5 days away, display day of the week and |
# HH:MM |
# HH:MM |
|
|
if ( $delta < $day * 5 ) { |
if ( $delta < $day * 5 ) { |
Line 752 to compute due to the amount of data tha
|
Line 438 to compute due to the amount of data tha
|
processed. |
processed. |
|
|
Apache::lonnavmaps provides an object model for manipulating this |
Apache::lonnavmaps provides an object model for manipulating this |
information in a higher-level fashion then directly manipulating |
information in a higher-level fashion than directly manipulating |
the hash. It also provides access to several auxilary functions |
the hash. It also provides access to several auxilary functions |
that aren't necessarily stored in the Big Hash, but are a per- |
that aren't necessarily stored in the Big Hash, but are a per- |
resource sort of value, like whether there is any feedback on |
resource sort of value, like whether there is any feedback on |
Line 798 Apache::lonnavmaps::render({}).
|
Line 484 Apache::lonnavmaps::render({}).
|
=head2 Overview of Columns |
=head2 Overview of Columns |
|
|
The renderer will build an HTML table for the navmap and return |
The renderer will build an HTML table for the navmap and return |
it. The table is consists of several columns, and a row for each |
it. The table consists of several columns, and a row for each |
resource (or possibly each part). You tell the renderer how many |
resource (or possibly each part). You tell the renderer how many |
columns to create and what to place in each column, optionally using |
columns to create and what to place in each column, optionally using |
one or more of the prepared columns, and the renderer will assemble |
one or more of the prepared columns, and the renderer will assemble |
Line 929 instruct the renderer to render only a p
|
Line 615 instruct the renderer to render only a p
|
the source of the map you want to process, like |
the source of the map you want to process, like |
'/res/103/jerf/navmap.course.sequence'. |
'/res/103/jerf/navmap.course.sequence'. |
|
|
|
=item * B<include_top_level_map>: default: false |
|
|
|
If you need to include the top level map (meaning the course) in the |
|
rendered output set this to true |
|
|
=item * B<navmap>: default: constructs one from %env |
=item * B<navmap>: default: constructs one from %env |
|
|
A reference to a navmap, used only if an iterator is not passed in. If |
A reference to a navmap, used only if an iterator is not passed in. If |
Line 1096 sub render_resource {
|
Line 787 sub render_resource {
|
|
|
if ($resource->is_problem()) { |
if ($resource->is_problem()) { |
if ($part eq '0' || $params->{'condensed'}) { |
if ($part eq '0' || $params->{'condensed'}) { |
$icon ='<img src="'.$location.'/problem.gif" alt="'.&mt('Problem').'" border="0" />'; |
$icon = '<img src="'.$location.'/'; |
|
if ($resource->is_task()) { |
|
$icon .= 'task.gif" alt="'.&mt('Task'); |
|
} else { |
|
$icon .= 'problem.gif" alt="'.&mt('Problem'); |
|
} |
|
$icon .='" border="0" />'; |
} else { |
} else { |
$icon = $params->{'indentString'}; |
$icon = $params->{'indentString'}; |
} |
} |
Line 1121 sub render_resource {
|
Line 818 sub render_resource {
|
($nowOpen ? &mt('Open Folder') : &mt('Close Folder')).' '.$title."\" border='0' />"; |
($nowOpen ? &mt('Open Folder') : &mt('Close Folder')).' '.$title."\" border='0' />"; |
|
|
$linkopen = "<a href=\"" . $params->{'url'} . '?' . |
$linkopen = "<a href=\"" . $params->{'url'} . '?' . |
$params->{'queryString'} . '&filter='; |
$params->{'queryString'} . '&filter='; |
$linkopen .= ($nowOpen xor $it->{CONDITION}) ? |
$linkopen .= ($nowOpen xor $it->{CONDITION}) ? |
addToFilter($filter, $mapId) : |
addToFilter($filter, $mapId) : |
removeFromFilter($filter, $mapId); |
removeFromFilter($filter, $mapId); |
$linkopen .= "&condition=" . $it->{CONDITION} . '&hereType=' |
$linkopen .= "&condition=" . $it->{CONDITION} . '&hereType=' |
. $params->{'hereType'} . '&here=' . |
. $params->{'hereType'} . '&here=' . |
&escape($params->{'here'}) . |
&escape($params->{'here'}) . |
'&jump=' . |
'&jump=' . |
&escape($resource->symb()) . |
&escape($resource->symb()) . |
"&folderManip=1\">"; |
"&folderManip=1\">"; |
|
|
} else { |
} else { |
# Don't allow users to manipulate folder |
# Don't allow users to manipulate folder |
Line 1152 sub render_resource {
|
Line 849 sub render_resource {
|
} |
} |
|
|
# We're done preparing and finally ready to start the rendering |
# We're done preparing and finally ready to start the rendering |
my $result = "<td align='left' valign='center'>"; |
my $result = "<td align='left' valign='middle'>"; |
|
|
my $indentLevel = $params->{'indentLevel'}; |
my $indentLevel = $params->{'indentLevel'}; |
if ($newBranchText) { $indentLevel--; } |
if ($newBranchText) { $indentLevel--; } |
Line 1216 sub render_communication_status {
|
Line 913 sub render_communication_status {
|
my $location=&Apache::loncommon::lonhttpdurl("/adm/lonMisc"); |
my $location=&Apache::loncommon::lonhttpdurl("/adm/lonMisc"); |
if ($resource->hasDiscussion()) { |
if ($resource->hasDiscussion()) { |
$discussionHTML = $linkopen . |
$discussionHTML = $linkopen . |
'<img border="0" src="'.$location.'/chat.gif" />' . |
'<img alt="'.&mt('New Discussion').'" border="0" src="'.$location.'/chat.gif" />' . |
$linkclose; |
$linkclose; |
} |
} |
|
|
if ($resource->getFeedback()) { |
if ($resource->getFeedback()) { |
my $feedback = $resource->getFeedback(); |
my $feedback = $resource->getFeedback(); |
foreach (split(/\,/, $feedback)) { |
foreach my $msgid (split(/\,/, $feedback)) { |
if ($_) { |
if ($msgid) { |
$feedbackHTML .= ' <a '.$target.' href="/adm/email?display=' |
$feedbackHTML .= ' <a '.$target.' href="/adm/email?display=' |
. &escape($_) . '">' |
. &escape($msgid) . '">' |
. '<img src="'.$location.'/feedback.gif" ' |
. '<img alt="'.&mt('New Email').'" src="'.$location.'/feedback.gif" ' |
. 'border="0" /></a>'; |
. 'border="0" /></a>'; |
} |
} |
} |
} |
Line 1235 sub render_communication_status {
|
Line 932 sub render_communication_status {
|
if ($resource->getErrors()) { |
if ($resource->getErrors()) { |
my $errors = $resource->getErrors(); |
my $errors = $resource->getErrors(); |
my $errorcount = 0; |
my $errorcount = 0; |
foreach (split(/,/, $errors)) { |
foreach my $msgid (split(/,/, $errors)) { |
last if ($errorcount>=10); # Only output 10 bombs maximum |
last if ($errorcount>=10); # Only output 10 bombs maximum |
if ($_) { |
if ($msgid) { |
$errorcount++; |
$errorcount++; |
$errorHTML .= ' <a '.$target.' href="/adm/email?display=' |
$errorHTML .= ' <a '.$target.' href="/adm/email?display=' |
. &escape($_) . '">' |
. &escape($msgid) . '">' |
. '<img src="'.$location.'/bomb.gif" ' |
. '<img alt="'.&mt('New Error').'" src="'.$location.'/bomb.gif" ' |
. 'border="0" /></a>'; |
. 'border="0" /></a>'; |
} |
} |
} |
} |
Line 1251 sub render_communication_status {
|
Line 948 sub render_communication_status {
|
$discussionHTML = $feedbackHTML = $errorHTML = ''; |
$discussionHTML = $feedbackHTML = $errorHTML = ''; |
} |
} |
|
|
return "<td width=\"75\" align=\"left\" valign=\"center\">$discussionHTML$feedbackHTML$errorHTML </td>"; |
return "<td width=\"75\" align=\"left\" valign=\"middle\">$discussionHTML$feedbackHTML$errorHTML </td>"; |
|
|
} |
} |
sub render_quick_status { |
sub render_quick_status { |
Line 1276 sub render_quick_status {
|
Line 973 sub render_quick_status {
|
if ($icon) { |
if ($icon) { |
my $location= |
my $location= |
&Apache::loncommon::lonhttpdurl("/adm/lonIcons/$icon"); |
&Apache::loncommon::lonhttpdurl("/adm/lonIcons/$icon"); |
$result .= "<td width='30' valign='center' width='50' align='right'>$linkopen<img width='25' height='25' src='$location' border='0' alt='$alt' />$linkclose</td>\n"; |
$result .= "<td valign='middle' width='50' align='right'>$linkopen<img width='25' height='25' src='$location' border='0' alt='$alt' />$linkclose</td>\n"; |
} else { |
} else { |
$result .= "<td width='30'> </td>\n"; |
$result .= "<td width='30'> </td>\n"; |
} |
} |
Line 1288 sub render_quick_status {
|
Line 985 sub render_quick_status {
|
} |
} |
sub render_long_status { |
sub render_long_status { |
my ($resource, $part, $params) = @_; |
my ($resource, $part, $params) = @_; |
my $result = "<td align='right' valign='center'>\n"; |
my $result = "<td align='right' valign='middle'>\n"; |
my $firstDisplayed = !$params->{'condensed'} && |
my $firstDisplayed = !$params->{'condensed'} && |
$params->{'multipart'} && $part eq "0"; |
$params->{'multipart'} && $part eq "0"; |
|
|
my $color; |
my $color; |
if ($resource->is_problem()) { |
if ($resource->is_problem() || $resource->is_practice()) { |
$color = $colormap{$resource->status}; |
$color = $colormap{$resource->status}; |
|
|
if (dueInLessThan24Hours($resource, $part) || |
if (dueInLessThan24Hours($resource, $part) || |
Line 1303 sub render_long_status {
|
Line 1000 sub render_long_status {
|
} |
} |
|
|
if ($resource->kind() eq "res" && |
if ($resource->kind() eq "res" && |
$resource->is_problem() && |
($resource->is_problem() || $resource->is_practice()) && |
!$firstDisplayed) { |
!$firstDisplayed) { |
if ($color) {$result .= "<font color=\"$color\"><b>"; } |
if ($color) {$result .= "<font color=\"$color\"><b>"; } |
$result .= getDescription($resource, $part); |
$result .= getDescription($resource, $part); |
if ($color) {$result .= "</b></font>"; } |
if ($color) {$result .= "</b></font>"; } |
} |
} |
if ($resource->is_map() && advancedUser() && $resource->randompick()) { |
if ($resource->is_map() && &advancedUser() && $resource->randompick()) { |
$result .= '(randomly select ' . $resource->randompick() .')'; |
$result .= &mt('(randomly select [_1])', $resource->randompick()); |
|
} |
|
if ($resource->is_map() && &advancedUser() && $resource->randomorder()) { |
|
$result .= &mt('(randomly ordered)'); |
} |
} |
|
|
# Debugging code |
# Debugging code |
Line 1444 sub render {
|
Line 1144 sub render {
|
# marker |
# marker |
my $filterHash = {}; |
my $filterHash = {}; |
# Figure out what we're not displaying |
# Figure out what we're not displaying |
foreach (split(/\,/, $env{"form.filter"})) { |
foreach my $item (split(/\,/, $env{"form.filter"})) { |
if ($_) { |
if ($item) { |
$filterHash->{$_} = "1"; |
$filterHash->{$item} = "1"; |
} |
} |
} |
} |
|
|
Line 1474 sub render {
|
Line 1174 sub render {
|
$navmap = Apache::lonnavmaps::navmap->new(); |
$navmap = Apache::lonnavmaps::navmap->new(); |
if (!defined($navmap)) { |
if (!defined($navmap)) { |
# no londer in course |
# no londer in course |
return '<font color="red">'.&mt('No course selected').'</font><br /> |
return '<span class="LC_error">'.&mt('No course selected').'</span><br /> |
<a href="/adm/roles">'.&mt('Select a course').'</a><br />'; |
<a href="/adm/roles">'.&mt('Select a course').'</a><br />'; |
} |
} |
} |
} |
Line 1552 sub render {
|
Line 1252 sub render {
|
|
|
$args->{'iterator'} = $it = $navmap->getIterator($firstResource, $finishResource, $filterHash, $condition); |
$args->{'iterator'} = $it = $navmap->getIterator($firstResource, $finishResource, $filterHash, $condition); |
} else { |
} else { |
$args->{'iterator'} = $it = $navmap->getIterator(undef, undef, $filterHash, $condition); |
$args->{'iterator'} = $it = $navmap->getIterator(undef, undef, $filterHash, $condition,undef,$args->{'include_top_level_map'}); |
} |
} |
} |
} |
|
|
Line 1612 sub render {
|
Line 1312 sub render {
|
if ($printCloseAll && !$args->{'resource_no_folder_link'}) { |
if ($printCloseAll && !$args->{'resource_no_folder_link'}) { |
my ($link,$text); |
my ($link,$text); |
if ($condition) { |
if ($condition) { |
$link='"navmaps?condition=0&filter=&'.$queryString. |
$link='"navmaps?condition=0&filter=&'.$queryString. |
'&here='.&escape($here).'"'; |
'&here='.&escape($here).'"'; |
$text='Close all folders'; |
$text='Close all folders'; |
} else { |
} else { |
$link='"navmaps?condition=1&filter=&'.$queryString. |
$link='"navmaps?condition=1&filter=&'.$queryString. |
'&here='.&escape($here).'"'; |
'&here='.&escape($here).'"'; |
$text='Open all folders'; |
$text='Open all folders'; |
} |
} |
Line 1663 END
|
Line 1363 END
|
|
|
if ($args->{'caller'} eq 'navmapsdisplay') { |
if ($args->{'caller'} eq 'navmapsdisplay') { |
$result .= '<table><tr><td>'. |
$result .= '<table><tr><td>'. |
&Apache::loncommon::help_open_menu('','Navigation Screen','Navigation_Screen','',undef,'RAT').'</td>'; |
&Apache::loncommon::help_open_menu('Navigation Screen','Navigation_Screen',undef,'RAT').'</td>'; |
if ($env{'environment.remotenavmap'} ne 'on') { |
if ($env{'environment.remotenavmap'} ne 'on') { |
$result .= '<td> </td>'; |
$result .= '<td> </td>'; |
} else { |
} else { |
Line 2120 See iterator documentation below.
|
Line 1820 See iterator documentation below.
|
use strict; |
use strict; |
use GDBM_File; |
use GDBM_File; |
use Apache::lonnet; |
use Apache::lonnet; |
|
use LONCAPA; |
|
|
sub new { |
sub new { |
# magic invocation to create a class instance |
# magic invocation to create a class instance |
Line 2219 sub generate_email_discuss_status {
|
Line 1920 sub generate_email_discuss_status {
|
my %lastread = &Apache::lonnet::dump('nohist_'.$cid.'_discuss', |
my %lastread = &Apache::lonnet::dump('nohist_'.$cid.'_discuss', |
$env{'user.domain'},$env{'user.name'},'lastread'); |
$env{'user.domain'},$env{'user.name'},'lastread'); |
my %lastreadtime = (); |
my %lastreadtime = (); |
foreach (keys %lastread) { |
foreach my $key (keys %lastread) { |
my $key = $_; |
my $shortkey = $key; |
$key =~ s/_lastread$//; |
$shortkey =~ s/_lastread$//; |
$lastreadtime{$key} = $lastread{$_}; |
$lastreadtime{$shortkey} = $lastread{$key}; |
} |
} |
|
|
my %feedback=(); |
my %feedback=(); |
Line 2232 sub generate_email_discuss_status {
|
Line 1933 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 $plain= |
my ($sendtime,$shortsubj,$fromname,$fromdomain,$status,$fromcid, |
&LONCAPA::unescape(&LONCAPA::unescape($msgid)); |
$symb,$error) = &Apache::lonmsg::unpackmsgid($msgid); |
if ($plain=~/ \[([^\]]+)\]\:/) { |
&Apache::lonenc::check_decrypt(\$symb); |
my $url=$1; |
if (($fromcid ne '') && ($fromcid ne $cid)) { |
if ($plain=~/\:Error \[/) { |
next; |
$error{$url}.=','.$msgid; |
} |
} else { |
if (defined($symb)) { |
$feedback{$url}.=','.$msgid; |
if (defined($error) && $error == 1) { |
} |
$error{$symb}.=','.$msgid; |
} |
} else { |
|
$feedback{$symb}.=','.$msgid; |
|
} |
|
} else { |
|
my $plain= |
|
&LONCAPA::unescape(&LONCAPA::unescape($msgid)); |
|
if ($plain=~/ \[([^\]]+)\]\:/) { |
|
my $url=$1; |
|
if ($plain=~/\:Error \[/) { |
|
$error{$url}.=','.$msgid; |
|
} else { |
|
$feedback{$url}.=','.$msgid; |
|
} |
|
} |
|
} |
} |
} |
} |
} |
|
|
#url's of resources that have feedbacks |
#symbs of resources that have feedbacks (will be urls pre-2.3) |
$self->{FEEDBACK} = \%feedback; |
$self->{FEEDBACK} = \%feedback; |
#or errors |
#or errors (will be urls pre 2.3) |
$self->{ERROR_MSG} = \%error; |
$self->{ERROR_MSG} = \%error; |
$self->{DISCUSSION_TIME} = \%discussiontime; |
$self->{DISCUSSION_TIME} = \%discussiontime; |
$self->{EMAIL_STATUS} = \%emailstatus; |
$self->{EMAIL_STATUS} = \%emailstatus; |
Line 2352 sub last_post_time {
|
Line 2067 sub last_post_time {
|
return $self->{DISCUSSION_TIME}->{$ressymb}; |
return $self->{DISCUSSION_TIME}->{$ressymb}; |
} |
} |
|
|
sub unread_discussion { |
sub discussion_info { |
my $self = shift; |
my $self = shift; |
my $symb = shift; |
my $symb = shift; |
|
my $filter = shift; |
|
|
$self->get_discussion_data(); |
$self->get_discussion_data(); |
|
|
my $ressymb = $self->wrap_symb($symb); |
my $ressymb = $self->wrap_symb($symb); |
# keys used to store bulletinboard postings use 'unwrapped' symb. |
# keys used to store bulletinboard postings use 'unwrapped' symb. |
my $discsymb = $self->unwrap_symb($ressymb); |
my $discsymb = &escape($self->unwrap_symb($ressymb)); |
my $version = $self->{DISCUSSION_DATA}{'version:'.$discsymb}; |
my $version = $self->{DISCUSSION_DATA}{'version:'.$discsymb}; |
if (!$version) { return; } |
if (!$version) { return; } |
|
|
my $prevread = $self->{LAST_READ}{$ressymb}; |
my $prevread = $self->{LAST_READ}{$ressymb}; |
|
|
my $unreadcount = 0; |
my $count = 0; |
my $hiddenflag = 0; |
my $hiddenflag = 0; |
my $deletedflag = 0; |
my $deletedflag = 0; |
my ($hidden,$deleted); |
my ($hidden,$deleted,%info); |
|
|
my %subjects; |
|
|
|
for (my $id=$version; $id>0; $id--) { |
for (my $id=$version; $id>0; $id--) { |
my $vkeys=$self->{DISCUSSION_DATA}{$id.':keys:'.$discsymb}; |
my $vkeys=$self->{DISCUSSION_DATA}{$id.':keys:'.$discsymb}; |
Line 2387 sub unread_discussion {
|
Line 2101 sub unread_discussion {
|
$deletedflag = 1; |
$deletedflag = 1; |
} |
} |
} else { |
} else { |
if (($hidden !~/\.$id\./) && ($deleted !~/\.$id\./) |
if (($hidden !~/\.$id\./) && ($deleted !~/\.$id\./)) { |
&& $prevread < $self->{DISCUSSION_DATA}{$id.':'.$discsymb.':timestamp'}) { |
if ($filter eq 'unread') { |
$unreadcount++; |
if ($prevread >= $self->{DISCUSSION_DATA}{$id.':'.$discsymb.':timestamp'}) { |
$subjects{$unreadcount}= |
next; |
$id.': '.$self->{DISCUSSION_DATA}{$id.':'.$discsymb.':subject'}; |
} |
} |
} |
|
$count++; |
|
$info{$count}{'subject'} = |
|
$self->{DISCUSSION_DATA}{$id.':'.$discsymb.':subject'}; |
|
$info{$count}{'id'} = $id; |
|
$info{$count}{'timestamp'} = $self->{DISCUSSION_DATA}{$id.':'.$discsymb.':timestamp'}; |
|
} |
} |
} |
} |
} |
if (wantarray) { |
if (wantarray) { |
return ($unreadcount,\%subjects); |
return ($count,%info); |
} |
} |
return $unreadcount |
return $count; |
} |
} |
|
|
sub wrap_symb { |
sub wrap_symb { |
Line 2429 sub unwrap_symb {
|
Line 2149 sub unwrap_symb {
|
sub getFeedback { |
sub getFeedback { |
my $self = shift; |
my $self = shift; |
my $symb = shift; |
my $symb = shift; |
|
my $source = shift; |
|
|
$self->generate_email_discuss_status(); |
$self->generate_email_discuss_status(); |
|
|
if (!defined($self->{FEEDBACK})) { return ""; } |
if (!defined($self->{FEEDBACK})) { return ""; } |
|
|
return $self->{FEEDBACK}->{$symb}; |
my $feedback; |
|
if ($self->{FEEDBACK}->{$symb}) { |
|
$feedback = $self->{FEEDBACK}->{$symb}; |
|
if ($self->{FEEDBACK}->{$source}) { |
|
$feedback .= ','.$self->{FEEDBACK}->{$source}; |
|
} |
|
} else { |
|
if ($self->{FEEDBACK}->{$source}) { |
|
$feedback = $self->{FEEDBACK}->{$source}; |
|
} |
|
} |
|
return $feedback; |
} |
} |
|
|
# Private method: Get the errors for that resource (by source). |
# Private method: Get the errors for that resource (by source). |
sub getErrors { |
sub getErrors { |
my $self = shift; |
my $self = shift; |
|
my $symb = shift; |
my $src = shift; |
my $src = shift; |
|
|
$self->generate_email_discuss_status(); |
$self->generate_email_discuss_status(); |
|
|
if (!defined($self->{ERROR_MSG})) { return ""; } |
if (!defined($self->{ERROR_MSG})) { return ""; } |
return $self->{ERROR_MSG}->{$src}; |
|
|
my $errors; |
|
if ($self->{ERROR_MSG}->{$symb}) { |
|
$errors = $self->{ERROR_MSG}->{$symb}; |
|
if ($self->{ERROR_MSG}->{$src}) { |
|
$errors .= ','.$self->{ERROR_MSG}->{$src}; |
|
} |
|
} else { |
|
if ($self->{ERROR_MSG}->{$src}) { |
|
$errors = $self->{ERROR_MSG}->{$src}; |
|
} |
|
} |
|
return $errors; |
} |
} |
|
|
=pod |
=pod |
Line 2471 the given map. This is one of the proper
|
Line 2216 the given map. This is one of the proper
|
|
|
# The strategy here is to cache the resource objects, and only construct them |
# The strategy here is to cache the resource objects, and only construct them |
# as we use them. The real point is to prevent reading any more from the tied |
# as we use them. The real point is to prevent reading any more from the tied |
# hash then we have to, which should hopefully alleviate speed problems. |
# hash than we have to, which should hopefully alleviate speed problems. |
|
|
sub getById { |
sub getById { |
my $self = shift; |
my $self = shift; |
Line 2545 sub finishResource {
|
Line 2290 sub finishResource {
|
# the actual lookup; parmval caches the results. |
# the actual lookup; parmval caches the results. |
sub parmval { |
sub parmval { |
my $self = shift; |
my $self = shift; |
my ($what,$symb)=@_; |
my ($what,$symb,$recurse)=@_; |
my $hashkey = $what."|||".$symb; |
my $hashkey = $what."|||".$symb; |
|
|
if (defined($self->{PARM_CACHE}->{$hashkey})) { |
if (defined($self->{PARM_CACHE}->{$hashkey})) { |
return $self->{PARM_CACHE}->{$hashkey}; |
return $self->{PARM_CACHE}->{$hashkey}; |
} |
} |
|
|
my $result = $self->parmval_real($what, $symb); |
my $result = $self->parmval_real($what, $symb, $recurse); |
$self->{PARM_CACHE}->{$hashkey} = $result; |
$self->{PARM_CACHE}->{$hashkey} = $result; |
return $result; |
return $result; |
} |
} |
Line 2662 sub parmval_real {
|
Line 2407 sub parmval_real {
|
if (defined($partgeneral)) { return $partgeneral; } |
if (defined($partgeneral)) { return $partgeneral; } |
} |
} |
if ($recurse) { return undef; } |
if ($recurse) { return undef; } |
my $pack_def=&Apache::lonnet::packages_tab_default($fn,'resource.'.$what); |
my $pack_def=&Apache::lonnet::packages_tab_default($fn,'resource.'.$rwhat); |
if (defined($pack_def)) { return $pack_def; } |
if (defined($pack_def)) { return $pack_def; } |
return ''; |
return ''; |
} |
} |
Line 2672 sub parmval_real {
|
Line 2417 sub parmval_real {
|
=item * B<getResourceByUrl>(url,multiple): |
=item * B<getResourceByUrl>(url,multiple): |
|
|
Retrieves a resource object by URL of the resource, unless the optional |
Retrieves a resource object by URL of the resource, unless the optional |
multiple parameter is included in wahich caes an array of resource |
multiple parameter is included in which case an array of resource |
objects is returned. If passed a resource object, it will simply return |
objects is returned. If passed a resource object, it will simply return |
it, so it is safe to use this method in code like |
it, so it is safe to use this method in code like |
"$res = $navmap->getResourceByUrl($res)" |
"$res = $navmap->getResourceByUrl($res)" |
Line 2707 all matching resources.
|
Line 2452 all matching resources.
|
|
|
=item * B<hasResource>(map, filterFunc, recursive, showall): |
=item * B<hasResource>(map, filterFunc, recursive, showall): |
|
|
Convience method for |
Convenience method for |
|
|
scalar(retrieveResources($map, $filterFunc, $recursive, 1, $showall)) > 0 |
scalar(retrieveResources($map, $filterFunc, $recursive, 1, $showall)) > 0 |
|
|
Line 2785 sub retrieveResources {
|
Line 2530 sub retrieveResources {
|
|
|
my @resources = (); |
my @resources = (); |
|
|
|
if (&$filterFunc($map)) { |
|
push(@resources, $map); |
|
} |
|
|
# Run down the iterator and collect the resources. |
# Run down the iterator and collect the resources. |
my $curRes; |
my $curRes; |
|
|
Line 2794 sub retrieveResources {
|
Line 2543 sub retrieveResources {
|
next; |
next; |
} |
} |
|
|
push @resources, $curRes; |
push(@resources, $curRes); |
|
|
if ($bailout) { |
if ($bailout) { |
return @resources; |
return @resources; |
Line 2941 be the tokens described above.
|
Line 2690 be the tokens described above.
|
|
|
Also note there is some old code floating around that trys to track |
Also note there is some old code floating around that trys 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 then |
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. |
|
|
=cut |
=cut |
Line 3125 sub next {
|
Line 2874 sub next {
|
$self->{HAVE_RETURNED_0} = 1; |
$self->{HAVE_RETURNED_0} = 1; |
return $self->{NAV_MAP}->getById('0.0'); |
return $self->{NAV_MAP}->getById('0.0'); |
} |
} |
|
if ($self->{RETURN_0} && !$self->{HAVE_RETURNED_0_BEGIN_MAP}) { |
|
$self->{HAVE_RETURNED_0_BEGIN_MAP} = 1; |
|
return $self->BEGIN_MAP(); |
|
} |
|
|
if ($self->{RECURSIVE_ITERATOR_FLAG}) { |
if ($self->{RECURSIVE_ITERATOR_FLAG}) { |
# grab the next from the recursive iterator |
# grab the next from the recursive iterator |
Line 3226 sub next {
|
Line 2979 sub next {
|
} |
} |
|
|
# Is this the end of a branch? If so, all of the resources examined above |
# Is this the end of a branch? If so, all of the resources examined above |
# led to lower levels then the one we are currently at, so we push a END_BRANCH |
# led to lower levels than the one we are currently at, so we push a END_BRANCH |
# marker onto the stack so we don't forget. |
# marker onto the stack so we don't forget. |
# Example: For the usual A(BC)(DE)F case, when the iterator goes down the |
# Example: For the usual A(BC)(DE)F case, when the iterator goes down the |
# BC branch and gets to C, it will see F as the only next resource, but it's |
# BC branch and gets to C, it will see F as the only next resource, but it's |
Line 3435 sub next {
|
Line 3188 sub next {
|
|
|
# filter the next possibilities to remove things we've |
# filter the next possibilities to remove things we've |
# already seen. |
# already seen. |
foreach (@$nextUnfiltered) { |
foreach my $item (@$nextUnfiltered) { |
if (!defined($self->{ALREADY_SEEN}->{$_->{ID}})) { |
if (!defined($self->{ALREADY_SEEN}->{$item->{ID}})) { |
push @$next, $_; |
push @$next, $item; |
} |
} |
} |
} |
|
|
Line 3562 X<symb> X<resource, symb>
|
Line 3315 X<symb> X<resource, symb>
|
All resources also have B<symb>s, which uniquely identify a resource |
All resources also have B<symb>s, which uniquely identify a resource |
in a course. Many internal LON-CAPA functions expect a symb. A symb |
in a course. Many internal LON-CAPA functions expect a symb. A symb |
carries along with it the URL of the resource, and the map it appears |
carries along with it the URL of the resource, and the map it appears |
in. Symbs are much larger then resource IDs. |
in. Symbs are much larger than resource IDs. |
|
|
=cut |
=cut |
|
|
Line 3638 false.
|
Line 3391 false.
|
|
|
=item * B<randompick>: |
=item * B<randompick>: |
|
|
Returns true for a map if the randompick feature is being used on the |
Returns the number of randomly picked items for a map if the randompick |
map. (?) |
feature is being used on the map. |
|
|
|
=item * B<randomorder>: |
|
|
|
Returns true for a map if the randomorder feature is being used on the |
|
map. |
|
|
=item * B<src>: |
=item * B<src>: |
|
|
Line 3671 sub randompick {
|
Line 3429 sub randompick {
|
my $self = shift; |
my $self = shift; |
return $self->parmval('randompick'); |
return $self->parmval('randompick'); |
} |
} |
|
sub randomorder { |
|
my $self = shift; |
|
return ($self->parmval('randomorder') =~ /^yes$/i); |
|
} |
sub link { |
sub link { |
my $self=shift; |
my $self=shift; |
if ($self->encrypted()) { return &Apache::lonenc::encrypted($self->src); } |
if ($self->encrypted()) { return &Apache::lonenc::encrypted($self->src); } |
Line 3747 sub compTitle {
|
Line 3509 sub compTitle {
|
} |
} |
return $title; |
return $title; |
} |
} |
|
|
=pod |
=pod |
|
|
B<Predicate Testing the Resource> |
B<Predicate Testing the Resource> |
Line 3833 sub contains_problem {
|
Line 3596 sub contains_problem {
|
} |
} |
return 0; |
return 0; |
} |
} |
|
sub map_contains_problem { |
|
my $self=shift; |
|
if ($self->is_map()) { |
|
my $has_problem= |
|
$self->hasResource($self,sub { $_[0]->is_problem() },1); |
|
return $has_problem; |
|
} |
|
return 0; |
|
} |
sub is_sequence { |
sub is_sequence { |
my $self=shift; |
my $self=shift; |
return $self->navHash("is_map_", 1) && |
return $self->navHash("is_map_", 1) && |
Line 3939 sub map_type {
|
Line 3711 sub map_type {
|
|
|
# These functions will be responsible for returning the CORRECT |
# These functions will be responsible for returning the CORRECT |
# VALUE for the parameter, no matter what. So while they may look |
# VALUE for the parameter, no matter what. So while they may look |
# like direct calls to parmval, they can be more then that. |
# like direct calls to parmval, they can be more than that. |
# So, for instance, the duedate function should use the "duedatetype" |
# So, for instance, the duedate function should use the "duedatetype" |
# information, rather then the resource object user. |
# information, rather than the resource object user. |
|
|
=pod |
=pod |
|
|
Line 4040 sub duedate {
|
Line 3812 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 (defined($interval)) { |
if ($interval =~ /\d+/) { |
my $first_access=&Apache::lonnet::get_first_access('map',$self->symb); |
my $first_access=&Apache::lonnet::get_first_access('map',$self->symb); |
if (defined($first_access)) { |
if (defined($first_access)) { |
$interval = $first_access+$interval; |
$interval = $first_access+$interval; |
Line 4055 sub duedate {
|
Line 3827 sub duedate {
|
} |
} |
sub handgrade { |
sub handgrade { |
(my $self, my $part) = @_; |
(my $self, my $part) = @_; |
|
my @response_ids = $self->responseIds($part); |
|
if (@response_ids) { |
|
foreach my $response_id (@response_ids) { |
|
if (lc($self->parmval("handgrade",$part.'_'.$response_id)) |
|
eq 'yes') { |
|
return 'yes'; |
|
} |
|
} |
|
} |
return $self->parmval("handgrade", $part); |
return $self->parmval("handgrade", $part); |
} |
} |
sub maxtries { |
sub maxtries { |
Line 4153 data was not extracted when the nav map
|
Line 3934 data was not extracted when the nav map
|
Returns a false value if there hasn't been discussion otherwise returns |
Returns a false value if there hasn't been discussion otherwise returns |
unix timestamp of last time a discussion posting (or edit) was made. |
unix timestamp of last time a discussion posting (or edit) was made. |
|
|
=item * B<unread_discussion>: |
=item * B<discussion_info>: |
|
|
returns in scalar context the count of the number of unread discussion |
optional argument is a filter (currently can be 'unread'); |
postings |
returns in scalar context the count of the number of discussion postings. |
|
|
returns in list context both the count of postings and a hash ref |
returns in list context both the count of postings and a hash ref |
containing the subjects of all unread postings |
containing information about the postings (subject, id, timestamp) in a hash. |
|
|
|
Default is to return counts for all postings. However if called with a second argument set to 'unread', will return information about only unread postings. |
|
|
=item * B<getFeedback>: |
=item * B<getFeedback>: |
|
|
Line 4168 for the resource, or the null string if
|
Line 3951 for the resource, or the null string if
|
email data was not extracted when the nav map was constructed. Usually |
email data was not extracted when the nav map was constructed. Usually |
used like this: |
used like this: |
|
|
for (split(/\,/, $res->getFeedback())) { |
for my $url (split(/\,/, $res->getFeedback())) { |
my $link = &escape($_); |
my $link = &escape($url); |
... |
... |
|
|
and use the link as appropriate. |
and use the link as appropriate. |
Line 4186 sub last_post_time {
|
Line 3969 sub last_post_time {
|
return $self->{NAV_MAP}->last_post_time($self->symb()); |
return $self->{NAV_MAP}->last_post_time($self->symb()); |
} |
} |
|
|
sub unread_discussion { |
sub discussion_info { |
my $self = shift; |
my ($self,$filter) = @_; |
return $self->{NAV_MAP}->unread_discussion($self->symb()); |
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(); |
if ($source =~ /^\/res\//) { $source = substr $source, 5; } |
if ($source =~ /^\/res\//) { $source = substr $source, 5; } |
return $self->{NAV_MAP}->getFeedback($source); |
return $self->{NAV_MAP}->getFeedback($symb,$source); |
} |
} |
|
|
sub getErrors { |
sub getErrors { |
my $self = shift; |
my $self = shift; |
my $source = $self->src(); |
my $source = $self->src(); |
|
my $symb = $self->symb(); |
if ($source =~ /^\/res\//) { $source = substr $source, 5; } |
if ($source =~ /^\/res\//) { $source = substr $source, 5; } |
return $self->{NAV_MAP}->getErrors($source); |
return $self->{NAV_MAP}->getErrors($symb,$source); |
} |
} |
|
|
=pod |
=pod |
Line 4363 sub extractParts {
|
Line 4148 sub extractParts {
|
$self->{PART_TYPE} = {}; |
$self->{PART_TYPE} = {}; |
return; |
return; |
} |
} |
foreach (split(/\,/,$metadata)) { |
foreach my $entry (split(/\,/,$metadata)) { |
if ($_ =~ /^(?:part|Task)_(.*)$/) { |
if ($entry =~ /^(?:part|Task)_(.*)$/) { |
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})) { |
Line 4389 sub extractParts {
|
Line 4174 sub extractParts {
|
|
|
|
|
# Init the responseIdHash |
# Init the responseIdHash |
foreach (@{$self->{PARTS}}) { |
foreach my $part (@{$self->{PARTS}}) { |
$responseIdHash{$_} = []; |
$responseIdHash{$part} = []; |
} |
} |
|
|
# Now, the unfortunate thing about this is that parts, part name, and |
# Now, the unfortunate thing about this is that parts, part name, and |
Line 4470 the completion information.
|
Line 4255 the completion information.
|
Idiomatic usage of these two methods would probably look something |
Idiomatic usage of these two methods would probably look something |
like |
like |
|
|
foreach ($resource->parts()) { |
foreach my $part ($resource->parts()) { |
my $dateStatus = $resource->getDateStatus($_); |
my $dateStatus = $resource->getDateStatus($part); |
my $completionStatus = $resource->getCompletionStatus($_); |
my $completionStatus = $resource->getCompletionStatus($part); |
|
|
or |
or |
|
|
my $status = $resource->status($_); |
my $status = $resource->status($part); |
|
|
... use it here ... |
... use it here ... |
} |
} |