version 1.428, 2009/02/25 15:25:21
|
version 1.468, 2011/11/27 22:51:28
|
Line 2
|
Line 2
|
# Navigate Maps Handler |
# Navigate Maps Handler |
# |
# |
# $Id$ |
# $Id$ |
|
|
# |
# |
# Copyright Michigan State University Board of Trustees |
# Copyright Michigan State University Board of Trustees |
# |
# |
Line 31
|
Line 32
|
|
|
=head1 NAME |
=head1 NAME |
|
|
Apache::lonnavmaps.pm |
Apache::lonnavmaps - Subroutines to handle and render the navigation |
|
|
=head1 SYNOPSIS |
=head1 SYNOPSIS |
|
|
Line 477 use Apache::loncommon();
|
Line 478 use Apache::loncommon();
|
use Apache::lonenc(); |
use Apache::lonenc(); |
use Apache::lonlocal; |
use Apache::lonlocal; |
use Apache::lonnet; |
use Apache::lonnet; |
|
use Apache::lonmap; |
|
|
use POSIX qw (floor strftime); |
use POSIX qw (floor strftime); |
use Time::HiRes qw( gettimeofday tv_interval ); |
use Time::HiRes qw( gettimeofday tv_interval ); |
use LONCAPA; |
use LONCAPA; |
use DateTime(); |
use DateTime(); |
|
|
|
# For debugging |
|
|
|
use Data::Dumper; |
|
|
|
|
# symbolic constants |
# symbolic constants |
sub SYMB { return 1; } |
sub SYMB { return 1; } |
sub URL { return 2; } |
sub URL { return 2; } |
Line 491 sub NOTHING { return 3; }
|
Line 499 sub NOTHING { return 3; }
|
|
|
my $resObj = "Apache::lonnavmaps::resource"; |
my $resObj = "Apache::lonnavmaps::resource"; |
|
|
# Keep these mappings in sync with lonquickgrades, which uses the colors |
# Keep these mappings in sync with lonquickgrades, which usesthe colors |
# instead of the icons. |
# instead of the icons. |
my %statusIconMap = |
my %statusIconMap = |
( |
( |
Line 504 my %statusIconMap =
|
Line 512 my %statusIconMap =
|
$resObj->ERROR => '' |
$resObj->ERROR => '' |
); |
); |
|
|
my %iconAltTags = |
my %iconAltTags = #texthash does not work here |
( 'navmap.correct.gif' => 'Correct', |
( 'navmap.correct.gif' => 'Correct', |
'navmap.wrong.gif' => 'Incorrect', |
'navmap.wrong.gif' => 'Incorrect', |
'navmap.open.gif' => 'Open' ); |
'navmap.open.gif' => 'Is Open', |
|
'navmap.partial.gif' => 'Partially Correct', |
|
'navmap.ellipsis.gif' => 'Attempted', |
|
); |
|
|
# Defines a status->color mapping, null string means don't color |
# Defines a status->color mapping, null string means don't color |
my %colormap = |
my %colormap = |
Line 523 my %colormap =
|
Line 534 my %colormap =
|
$resObj->OPEN => '', |
$resObj->OPEN => '', |
$resObj->NOTHING_SET => '', |
$resObj->NOTHING_SET => '', |
$resObj->ATTEMPTED => '', |
$resObj->ATTEMPTED => '', |
|
$resObj->CREDIT_ATTEMPTED => '', |
$resObj->ANSWER_SUBMITTED => '', |
$resObj->ANSWER_SUBMITTED => '', |
$resObj->PARTIALLY_CORRECT => '#006600' |
$resObj->PARTIALLY_CORRECT => '#006600' |
); |
); |
Line 530 my %colormap =
|
Line 542 my %colormap =
|
# is not yet done and due in less than 24 hours |
# is not yet done and due in less than 24 hours |
my $hurryUpColor = "#FF0000"; |
my $hurryUpColor = "#FF0000"; |
|
|
sub close { |
my $future_slots_checked = 0; |
if ($env{'environment.remotenavmap'} ne 'on') { return ''; } |
my $future_slots = 0; |
return(<<ENDCLOSE); |
|
<script type="text/javascript"> |
|
window.status='Accessing Nav Control'; |
|
menu=window.open("/adm/rat/empty.html","loncapanav", |
|
"height=600,width=400,scrollbars=1"); |
|
window.status='Closing Nav Control'; |
|
menu.close(); |
|
window.status='Done.'; |
|
</script> |
|
ENDCLOSE |
|
} |
|
|
|
sub update { |
|
if ($env{'environment.remotenavmap'} ne 'on') { return ''; } |
|
if (!$env{'request.course.id'}) { return ''; } |
|
if ($ENV{'REQUEST_URI'}=~m|^/adm/navmaps|) { return ''; } |
|
return(<<ENDUPDATE); |
|
<form name="navform"></form> |
|
<script type="text/javascript"> |
|
this.document.navform.action='/adm/navmaps#curloc'; |
|
this.document.navform.target='loncapanav'; |
|
this.document.navform.submit(); |
|
</script> |
|
ENDUPDATE |
|
} |
|
|
|
|
|
sub addToFilter { |
sub addToFilter { |
my $hashIn = shift; |
my $hashIn = shift; |
Line 594 sub getLinkForResource {
|
Line 580 sub getLinkForResource {
|
my ($map,$id,$src)=&Apache::lonnet::decode_symb($res->symb()); |
my ($map,$id,$src)=&Apache::lonnet::decode_symb($res->symb()); |
if ($map=~/\.page$/) { |
if ($map=~/\.page$/) { |
my $url=&Apache::lonnet::clutter($map); |
my $url=&Apache::lonnet::clutter($map); |
$anchor=&escape($src->shown_symb()); |
$anchor=&escape($res->shown_symb()); |
return ($url,$res->shown_symb(),$anchor); |
return ($url,$res->shown_symb(),$anchor); |
} |
} |
} |
} |
Line 629 sub getDescription {
|
Line 615 sub getDescription {
|
return &mt("Having technical difficulties; please check status later"); |
return &mt("Having technical difficulties; please check status later"); |
} |
} |
if ($status == $res->NOTHING_SET) { |
if ($status == $res->NOTHING_SET) { |
return &mt("Not currently assigned."); |
return &Apache::lonhtmlcommon::direct_parm_link(&mt("Not currently assigned.",$res->symb(),'opendate'),$part); |
} |
} |
if ($status == $res->OPEN_LATER) { |
if ($status == $res->OPEN_LATER) { |
return &mt("Open ") .timeToHumanString($open,'start'); |
return &mt("Open [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($open,'start'),$res->symb(),'opendate',$part)); |
|
} |
|
if ($res->simpleStatus($part) == $res->OPEN) { |
|
unless (&Apache::lonnet::allowed('mgr',$env{'request.course.id'})) { |
|
my ($slot_status,$slot_time,$slot_name)=$res->check_for_slot($part); |
|
if ($slot_status == $res->UNKNOWN) { |
|
return &mt('Reservation status unknown'); |
|
} elsif ($slot_status == $res->RESERVED) { |
|
return &mt('Reserved - ends [_1]', |
|
timeToHumanString($slot_time,'end')); |
|
} elsif ($slot_status == $res->RESERVED_LOCATION) { |
|
return &mt('Reserved - specific location(s) - ends [_1]', |
|
timeToHumanString($slot_time,'end')); |
|
} elsif ($slot_status == $res->RESERVED_LATER) { |
|
return &mt('Reserved - next open [_1]', |
|
timeToHumanString($slot_time,'start')); |
|
} elsif ($slot_status == $res->RESERVABLE) { |
|
return &mt('Reservable ending [_1]', |
|
timeToHumanString($slot_time,'end')); |
|
} elsif ($slot_status == $res->RESERVABLE_LATER) { |
|
return &mt('Reservable starting [_1]', |
|
timeToHumanString($slot_time,'start')); |
|
} elsif ($slot_status == $res->NOT_IN_A_SLOT) { |
|
return &mt('Reserve a time/place to work'); |
|
} elsif ($slot_status == $res->NOTRESERVABLE) { |
|
return &mt('Reservation not available'); |
|
} elsif ($slot_status == $res->WAITING_FOR_GRADE) { |
|
return &mt('Submission in grading queue'); |
|
} |
|
} |
} |
} |
if ($status == $res->OPEN) { |
if ($status == $res->OPEN) { |
if ($due) { |
if ($due) { |
if ($res->is_practice()) { |
if ($res->is_practice()) { |
return &mt("Closes ")." " .timeToHumanString($due,'start'); |
return &mt("Closes [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'start'),$res->symb(),'duedate',$part)); |
} else { |
} else { |
return &mt("Due")." " .timeToHumanString($due,'end'); |
return &mt("Due [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'end'),$res->symb(),'duedate',$part)); |
} |
} |
} else { |
} else { |
return &mt("Open, no due date"); |
return &Apache::lonhtmlcommon::direct_parm_link(&mt("Open, no due date"),$res->symb(),'duedate',$part); |
} |
} |
} |
} |
if ($status == $res->PAST_DUE_ANSWER_LATER) { |
if ($status == $res->PAST_DUE_ANSWER_LATER) { |
return &mt("Answer open")." " .timeToHumanString($answer,'start'); |
return &mt("Answer open [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($answer,'start'),$res->symb(),'answerdate',$part)); |
} |
} |
if ($status == $res->PAST_DUE_NO_ANSWER) { |
if ($status == $res->PAST_DUE_NO_ANSWER) { |
if ($res->is_practice()) { |
if ($res->is_practice()) { |
return &mt("Closed")." " . timeToHumanString($due,'start'); |
return &mt("Closed [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'start'),$res->symb(),'answerdate,duedate',$part)); |
} else { |
} else { |
return &mt("Was due")." " . timeToHumanString($due,'end'); |
return &mt("Was due [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'end'),$res->symb(),'answerdate,duedate',$part)); |
} |
} |
} |
} |
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') { |
return &mt("Answer available"); |
return &Apache::lonhtmlcommon::direct_parm_link(&mt("Answer available"),$res->symb(),'answerdate,duedate',$part); |
} |
} |
if ($status == $res->EXCUSED) { |
if ($status == $res->EXCUSED) { |
return &mt("Excused by instructor"); |
return &mt("Excused by instructor"); |
} |
} |
if ($status == $res->ATTEMPTED) { |
if ($status == $res->ATTEMPTED) { |
return &mt("Answer submitted, not yet graded"); |
if ($res->is_anonsurvey($part) || $res->is_survey($part)) { |
|
return &mt("Survey submission recorded"); |
|
} else { |
|
return &mt("Answer submitted, not yet graded"); |
|
} |
|
} |
|
if ($status == $res->CREDIT_ATTEMPTED) { |
|
if ($res->is_anonsurvey($part) || $res->is_survey($part)) { |
|
return &mt("Credit for survey submission"); |
|
} |
} |
} |
if ($status == $res->TRIES_LEFT) { |
if ($status == $res->TRIES_LEFT) { |
my $tries = $res->tries($part); |
my $tries = $res->tries($part); |
Line 676 sub getDescription {
|
Line 700 sub getDescription {
|
} |
} |
} |
} |
if ($due) { |
if ($due) { |
return &mt("Due")." " . timeToHumanString($due,'end') . |
return &mt("Due [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'end'),$res->symb(),'duedate',$part)) . |
" $triesString"; |
" $triesString"; |
} else { |
} else { |
return &mt("No due date")." $triesString"; |
return &Apache::lonhtmlcommon::direct_parm_link(&mt("No due date"),$res->symb(),'duedate',$part)." $triesString"; |
} |
} |
} |
} |
if ($status == $res->ANSWER_SUBMITTED) { |
if ($status == $res->ANSWER_SUBMITTED) { |
Line 761 sub timeToHumanString {
|
Line 785 sub timeToHumanString {
|
|
|
# Less than an hour |
# Less than an hour |
if ( $delta < $hour ) { |
if ( $delta < $hour ) { |
# If so, use minutes |
# If so, use minutes; or minutes, seconds (if format requires) |
my $minutes = floor($delta / 60); |
my $minutes = floor($delta / 60); |
|
if (($format ne '') && ($format =~ /\%(T|S)/)) { |
|
my $display; |
|
if ($minutes == 1) { |
|
$display = "${prefix}1 minute"; |
|
} else { |
|
$display = "$prefix$minutes minutes"; |
|
} |
|
my $seconds = $delta % $minute; |
|
if ($seconds == 0) { |
|
$display .= $tense; |
|
} elsif ($seconds == 1) { |
|
$display .= ", 1 second$tense"; |
|
} else { |
|
$display .= ", $seconds seconds$tense"; |
|
} |
|
return $display; |
|
} |
if ($minutes == 1) { return "${prefix}1 minute$tense"; } |
if ($minutes == 1) { return "${prefix}1 minute$tense"; } |
return "$prefix$minutes minutes$tense"; |
return "$prefix$minutes minutes$tense"; |
} |
} |
|
|
# Is it less than 24 hours away? If so, |
# Is it less than 24 hours away? If so, |
# display hours + minutes |
# display hours + minutes, (and + seconds, if format specified it) |
if ( $delta < $hour * 24) { |
if ( $delta < $hour * 24) { |
my $hours = floor($delta / $hour); |
my $hours = floor($delta / $hour); |
my $minutes = floor(($delta % $hour) / $minute); |
my $minutes = floor(($delta % $hour) / $minute); |
Line 783 sub timeToHumanString {
|
Line 824 sub timeToHumanString {
|
if ($minutes == 0) { |
if ($minutes == 0) { |
$minuteString = ""; |
$minuteString = ""; |
} |
} |
|
if (($format ne '') && ($format =~ /\%(T|S)/)) { |
|
my $display = "$prefix$hourString$minuteString"; |
|
my $seconds = $delta-(($hours * $hour)+($minutes * $minute)); |
|
if ($seconds == 0) { |
|
$display .= $tense; |
|
} elsif ($seconds == 1) { |
|
$display .= ", 1 second$tense"; |
|
} else { |
|
$display .= ", $seconds seconds$tense"; |
|
} |
|
return $display; |
|
} |
return "$prefix$hourString$minuteString$tense"; |
return "$prefix$hourString$minuteString$tense"; |
} |
} |
|
|
|
# Date/time is more than 24 hours away |
|
|
my $dt = DateTime->from_epoch(epoch => $time) |
my $dt = DateTime->from_epoch(epoch => $time) |
->set_time_zone(&Apache::lonlocal::gettimezone()); |
->set_time_zone(&Apache::lonlocal::gettimezone()); |
|
|
# If there's a caller supplied format, use it. |
# If there's a caller supplied format, use it, unless it only displays |
|
# H:M:S or H:M. |
|
|
if ($format ne '') { |
if (($format ne '') && ($format ne '%T') && ($format ne '%R')) { |
my $timeStr = $dt->strftime($format); |
my $timeStr = $dt->strftime($format); |
return $timeStr.' ('.$dt->time_zone_short_name().')'; |
return $timeStr.' ('.$dt->time_zone_short_name().')'; |
} |
} |
Line 848 sub render_resource {
|
Line 904 sub render_resource {
|
my $link = $params->{"resourceLink"}; |
my $link = $params->{"resourceLink"}; |
|
|
# 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... |
# The stuff to the left of the ? must have ' replaced by \' since |
|
# it will be quoted with ' in the href. |
|
|
|
my ($left,$right) = split(/\?/, $link); |
|
$link = $left.'?'.$right; |
|
|
|
my $src = $resource->src(); |
my $src = $resource->src(); |
my $it = $params->{"iterator"}; |
my $it = $params->{"iterator"}; |
Line 865 sub render_resource {
|
Line 916 sub render_resource {
|
my $location=&Apache::loncommon::lonhttpdurl("/adm/lonIcons"); |
my $location=&Apache::loncommon::lonhttpdurl("/adm/lonIcons"); |
# If this is a new branch, label it so |
# If this is a new branch, label it so |
if ($params->{'isNewBranch'}) { |
if ($params->{'isNewBranch'}) { |
$newBranchText = "<img src='$location/branch.gif' alt='Branch' />"; |
$newBranchText = "<img src='$location/branch.gif' alt=".mt('Branch')." />"; |
} |
} |
|
|
# links to open and close the folder |
# links to open and close the folder |
Line 932 sub render_resource {
|
Line 983 sub render_resource {
|
} |
} |
|
|
if ($resource->randomout()) { |
if ($resource->randomout()) { |
$nonLinkedText .= ' <i>('.&mt('hidden').')</i> '; |
$nonLinkedText .= ' <span class="LC_warning">('.&mt('hidden').')</span> '; |
} |
} |
if (!$resource->condval()) { |
if (!$resource->condval()) { |
$nonLinkedText .= ' <i>('.&mt('conditionally hidden').')</i> '; |
$nonLinkedText .= ' <span class="LC_info">('.&mt('conditionally hidden').')</span> '; |
} |
} |
if (($resource->is_practice()) && ($resource->is_raw_problem())) { |
if (($resource->is_practice()) && ($resource->is_raw_problem())) { |
$nonLinkedText .=' <font color="green"><b>'.&mt('not graded').'</b></font>'; |
$nonLinkedText .=' <font color="green"><b>'.&mt('not graded').'</b></font>'; |
Line 962 sub render_resource {
|
Line 1013 sub render_resource {
|
# Is this the current resource? |
# Is this the current resource? |
if (!$params->{'displayedHereMarker'} && |
if (!$params->{'displayedHereMarker'} && |
$resource->symb() eq $params->{'here'} ) { |
$resource->symb() eq $params->{'here'} ) { |
$curMarkerBegin = '<em style="font-weight:bold;">'; |
$curMarkerBegin = '<em>'; |
$curMarkerEnd = '</em>'; |
$curMarkerEnd = '</em>'; |
$params->{'displayedHereMarker'} = 1; |
$params->{'displayedHereMarker'} = 1; |
} |
} |
Line 979 sub render_resource {
|
Line 1030 sub render_resource {
|
$nonLinkedText .= ' ('.&mt('[_1] parts', $resource->countParts()).')'; |
$nonLinkedText .= ' ('.&mt('[_1] parts', $resource->countParts()).')'; |
} |
} |
|
|
my $target; |
|
if ($env{'environment.remotenavmap'} eq 'on') { |
|
$target=' target="loncapaclient" '; |
|
} |
|
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 $target href=\"$link\">$title$partLabel</a>$curMarkerEnd$nonLinkedText</td>"; |
$result .= "$curMarkerBegin<a href=\"$link\">$title$partLabel</a>$curMarkerEnd$nonLinkedText</td>"; |
} else { |
} else { |
$result .= "$curMarkerBegin$linkopen$title$partLabel</a>$curMarkerEnd$nonLinkedText</td>"; |
$result .= "$curMarkerBegin$linkopen$title$partLabel</a>$curMarkerEnd$nonLinkedText</td>"; |
} |
} |
Line 997 sub render_communication_status {
|
Line 1044 sub render_communication_status {
|
my $discussionHTML = ""; my $feedbackHTML = ""; my $errorHTML = ""; |
my $discussionHTML = ""; my $feedbackHTML = ""; my $errorHTML = ""; |
|
|
my $link = $params->{"resourceLink"}; |
my $link = $params->{"resourceLink"}; |
my $target; |
my $linkopen = "<a href=\"$link\">"; |
if ($env{'environment.remotenavmap'} eq 'on') { |
|
$target=' target="loncapaclient" '; |
|
} |
|
my $linkopen = "<a $target href=\"$link\">"; |
|
my $linkclose = "</a>"; |
my $linkclose = "</a>"; |
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 alt="'.&mt('New Discussion').'" src="'.$location.'/chat.gif" />' . |
'<img alt="'.&mt('New Discussion').'" src="'.$location.'/chat.gif" title="'.&mt('New Discussion').'"/>' . |
$linkclose; |
$linkclose; |
} |
} |
|
|
Line 1014 sub render_communication_status {
|
Line 1057 sub render_communication_status {
|
my $feedback = $resource->getFeedback(); |
my $feedback = $resource->getFeedback(); |
foreach my $msgid (split(/\,/, $feedback)) { |
foreach my $msgid (split(/\,/, $feedback)) { |
if ($msgid) { |
if ($msgid) { |
$feedbackHTML .= ' <a '.$target.' href="/adm/email?display=' |
$feedbackHTML .= ' <a href="/adm/email?display=' |
. &escape($msgid) . '">' |
. &escape($msgid) . '">' |
. '<img alt="'.&mt('New E-mail').'" src="'.$location.'/feedback.gif" /></a>'; |
. '<img alt="'.&mt('New E-mail').'" src="'.$location.'/feedback.gif" title="'.&mt('New E-mail').'"/></a>'; |
} |
} |
} |
} |
} |
} |
Line 1028 sub render_communication_status {
|
Line 1071 sub render_communication_status {
|
last if ($errorcount>=10); # Only output 10 bombs maximum |
last if ($errorcount>=10); # Only output 10 bombs maximum |
if ($msgid) { |
if ($msgid) { |
$errorcount++; |
$errorcount++; |
$errorHTML .= ' <a '.$target.' href="/adm/email?display=' |
$errorHTML .= ' <a href="/adm/email?display=' |
. &escape($msgid) . '">' |
. &escape($msgid) . '">' |
. '<img alt="'.&mt('New Error').'" src="'.$location.'/bomb.gif" /></a>'; |
. '<img alt="'.&mt('New Error').'" src="'.$location.'/bomb.gif" title="'.&mt('New Error').'"/></a>'; |
} |
} |
} |
} |
} |
} |
Line 1048 sub render_quick_status {
|
Line 1091 sub render_quick_status {
|
$params->{'multipart'} && $part eq "0"; |
$params->{'multipart'} && $part eq "0"; |
|
|
my $link = $params->{"resourceLink"}; |
my $link = $params->{"resourceLink"}; |
my $target; |
my $linkopen = "<a href=\"$link\">"; |
if ($env{'environment.remotenavmap'} eq 'on') { |
|
$target=' target="loncapaclient" '; |
|
} |
|
my $linkopen = "<a $target href=\"$link\">"; |
|
my $linkclose = "</a>"; |
my $linkclose = "</a>"; |
|
|
$result .= '<td class="LC_middle">'; |
$result .= '<td class="LC_middle">'; |
Line 1063 sub render_quick_status {
|
Line 1102 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 .= "$linkopen<img src='$location' alt='$alt' />$linkclose"; |
$result .= $linkopen.'<img src="'.$location.'" alt="'.&mt($alt).'" title="'.&mt($alt).'" />'.$linkclose; |
} else { |
} else { |
$result .= " "; |
$result .= " "; |
} |
} |
Line 1090 sub render_long_status {
|
Line 1129 sub render_long_status {
|
} |
} |
|
|
if ($resource->kind() eq "res" && |
if ($resource->kind() eq "res" && |
($resource->is_problem() || $resource->is_practice()) && |
$resource->is_raw_problem() && |
!$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()) { |
|
if (&Apache::lonnet::allowed('mdc')) { |
|
if ($resource->symb=~/^uploaded/) { |
|
$result.=" <a href='/adm/coursedocs?command=direct&symb=".&escape($resource->symb())."'>". |
|
"<span class='LC_setting'>".&mt("Edit Content").'</span></a> '; |
|
} |
|
} |
|
} |
if ($resource->is_map() && &advancedUser() && $resource->randompick()) { |
if ($resource->is_map() && &advancedUser() && $resource->randompick()) { |
$result .= &mt('(randomly select [_1])', $resource->randompick()); |
$result .= &mt('(randomly select [_1])', $resource->randompick()); |
} |
} |
Line 1387 sub render {
|
Line 1434 sub render {
|
my $location=&Apache::loncommon::lonhttpdurl("/adm/lonMisc"); |
my $location=&Apache::loncommon::lonhttpdurl("/adm/lonMisc"); |
if ($navmap->{LAST_CHECK}) { |
if ($navmap->{LAST_CHECK}) { |
$result .= |
$result .= |
'<img src="'.$location.'/chat.gif"> '.&mt('New discussion since').' '. |
'<img src="'.$location.'/chat.gif" alt="" /> '.&mt('New discussion since').' '. |
strftime("%A, %b %e at %I:%M %P", localtime($navmap->{LAST_CHECK})). |
strftime("%A, %b %e at %I:%M %P", localtime($navmap->{LAST_CHECK})). |
'</td><td align="center" valign="bottom"> '. |
'</td><td align="center" valign="bottom"> '. |
'<img src="'.$location.'/feedback.gif"> '.&mt('New message (click to open)').'<p>'. |
'<img src="'.$location.'/feedback.gif" alt="" /> '.&mt('New message (click to open)').'<p>'. |
'</td>'; |
'</td>'; |
} else { |
} else { |
$result .= '<td align="center" valign="bottom"> '. |
$result .= '<td align="center" valign="bottom"> '. |
'<img src="'.$location.'/chat.gif"> '.&mt('Discussions').'</td><td align="center" valign="bottom">'. |
'<img src="'.$location.'/chat.gif" alt="" /> '.&mt('Discussions').'</td><td align="center" valign="bottom">'. |
' <img src="'.$location.'/feedback.gif"> '.&mt('New message (click to open)'). |
' <img src="'.$location.'/feedback.gif" alt="" /> '.&mt('New message (click to open)'). |
'</td>'; |
'</td>'; |
} |
} |
|
|
Line 1405 sub render {
|
Line 1452 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'; |
} |
} |
|
if ($env{'form.register'}) { |
|
$link .= '&register='.$env{'form.register'}; |
|
} |
if ($args->{'caller'} eq 'navmapsdisplay') { |
if ($args->{'caller'} eq 'navmapsdisplay') { |
&add_linkitem($args->{'linkitems'},'changefolder', |
&add_linkitem($args->{'linkitems'},'changefolder', |
'location.href='.$link,$text); |
"location.href='$link'",$text); |
} else { |
} else { |
$result.='<a href='.$link.'>'.&mt($text).'</a>'; |
$result.= '<a href="'.$link.'">'.&mt($text).'</a>'; |
} |
} |
$result .= "\n"; |
$result .= "\n"; |
} |
} |
Line 1433 sub render {
|
Line 1483 sub render {
|
<input type="hidden" name="navurl" value="$ENV{'QUERY_STRING'}" /> |
<input type="hidden" name="navurl" value="$ENV{'QUERY_STRING'}" /> |
<input type="hidden" name="navtime" value="$time" /> |
<input type="hidden" name="navtime" value="$time" /> |
END |
END |
|
if ($env{'form.register'}) { |
|
$result .= '<input type="hidden" name="register" value="'.$env{'form.register'}.'" />'; |
|
} |
if ($args->{'sort'} eq 'discussion') { |
if ($args->{'sort'} eq 'discussion') { |
my $totdisc = 0; |
my $totdisc = 0; |
my $haveDisc = ''; |
my $haveDisc = ''; |
Line 1454 END
|
Line 1507 END
|
$result.='</form>'; |
$result.='</form>'; |
} |
} |
|
|
|
|
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') { |
|
$result .= '<td> </td>'; |
$result .= '<td> </td>'; |
} else { |
$result.='<td class="LC_middle">'.&mt('Tools:').'</td>'; |
$result .= '</tr><tr>'; |
$result.=&show_linkitems_toolbar($args->{'linkitems'}); |
} |
|
$result.=&show_linkitems($args->{'linkitems'}); |
|
if ($args->{'sort_html'}) { |
if ($args->{'sort_html'}) { |
if ($env{'environment.remotenavmap'} ne 'on') { |
$result.='<td> </td><td> </td><td> </td>'. |
$result.='<td> </td><td> </td><td> </td>'. |
'<td align="right">'.$args->{'sort_html'}.'</td></tr>'; |
'<td align="right">'.$args->{'sort_html'}.'</td></tr>'; |
} |
} else { |
|
$result.='</tr><tr><td align="left"><br />'. |
|
$args->{'sort_html'}.'</td></tr>'; |
|
} |
|
} |
|
$result .= '</table>'; |
$result .= '</table>'; |
} elsif ($args->{'sort_html'}) { |
} elsif ($args->{'sort_html'}) { |
$result.=$args->{'sort_html'}; |
$result.=$args->{'sort_html'}; |
Line 1486 END
|
Line 1530 END
|
} |
} |
# End parameter setting |
# End parameter setting |
|
|
$result .= "\n<table id=\"LC_nav_location\">\n<tbody>\n<tr>\n<td class=\"LC_current_location\"> </td>\n</tr>\n</tbody>\n</table>\n"; |
|
$result .= "<br />\n"; |
$result .= "<br />\n"; |
|
|
# Data |
# Data |
$result .= '<table id="LC_tableOfContent">' ."\n"; |
$result.=&Apache::loncommon::start_data_table("LC_tableOfContent"); |
|
|
my $res = "Apache::lonnavmaps::resource"; |
my $res = "Apache::lonnavmaps::resource"; |
my %condenseStatuses = |
my %condenseStatuses = |
( $res->NETWORK_FAILURE => 1, |
( $res->NETWORK_FAILURE => 1, |
$res->NOTHING_SET => 1, |
$res->NOTHING_SET => 1, |
$res->CORRECT => 1 ); |
$res->CORRECT => 1 ); |
my @backgroundColors = ("LC_trEven", "LC_trOdd"); |
|
|
|
# Shared variables |
# Shared variables |
$args->{'counter'} = 0; # counts the rows |
$args->{'counter'} = 0; # counts the rows |
Line 1725 END
|
Line 1767 END
|
if (defined($anchor)) { $anchor='#'.$anchor; } |
if (defined($anchor)) { $anchor='#'.$anchor; } |
my $srcHasQuestion = $src =~ /\?/; |
my $srcHasQuestion = $src =~ /\?/; |
$args->{"resourceLink"} = $src. |
$args->{"resourceLink"} = $src. |
($srcHasQuestion?'&':'?') . |
($srcHasQuestion?'&':'?') . |
'symb=' . &escape($symb).$anchor; |
'symb=' . &escape($symb).$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. |
foreach my $part (@parts) { |
foreach my $part (@parts) { |
$rownum ++; |
$rownum ++; |
my $backgroundColor = $backgroundColors[$rownum % scalar(@backgroundColors)]; |
|
|
|
$result .= " <tr class='$backgroundColor'>\n"; |
$result .= &Apache::loncommon::start_data_table_row(); |
|
|
# Set up some data about the parts that the cols might want |
# Set up some data about the parts that the cols might want |
my $filter = $it->{FILTER}; |
my $filter = $it->{FILTER}; |
Line 1760 END
|
Line 1801 END
|
} |
} |
$result .= $colHTML . "\n"; |
$result .= $colHTML . "\n"; |
} |
} |
$result .= " </tr>\n"; |
$result .= &Apache::loncommon::end_data_table_row(); |
$args->{'isNewBranch'} = 0; |
$args->{'isNewBranch'} = 0; |
} |
} |
|
|
Line 1788 END
|
Line 1829 END
|
# it's quite likely this might fix other browsers, too, and |
# it's quite likely this might fix other browsers, too, and |
# certainly won't hurt anything. |
# certainly won't hurt anything. |
if ($displayedJumpMarker) { |
if ($displayedJumpMarker) { |
$result .= " |
$result .= &Apache::lonhtmlcommon::scripttag(" |
<script> |
|
if (location.href.indexOf('#curloc')==-1) { |
if (location.href.indexOf('#curloc')==-1) { |
setTimeout(\"location += '#curloc';\", 0) |
setTimeout(\"location += '#curloc';\", 0) |
} |
} |
</script>"; |
"); |
} |
} |
|
|
$result .= "</table>"; |
$result.=&Apache::loncommon::end_data_table(); |
|
|
if ($r) { |
if ($r) { |
$r->print($result); |
$r->print($result); |
$result = ""; |
$result = ""; |
Line 1813 sub add_linkitem {
|
Line 1853 sub add_linkitem {
|
$$linkitems{$name}{'text'}=&mt($text); |
$$linkitems{$name}{'text'}=&mt($text); |
} |
} |
|
|
sub show_linkitems { |
sub show_linkitems_toolbar { |
my ($linkitems)=@_; |
my ($linkitems,$condition)=@_; |
my @linkorder = ("blank","launchnav","closenav","firsthomework", |
my @linkorder = ('firsthomework','everything','uncompleted', |
"everything","uncompleted","changefolder","clearbubbles"); |
'changefolder','clearbubbles'); |
|
my $result .='<td align="left">'."\n". |
my $result .= (<<ENDBLOCK); |
'<span class="LC_nobreak">'."\n". |
<td align="left"> |
'<ul id="LC_toolbar">'; |
<script type="text/javascript"> |
|
function changeNavDisplay () { |
|
var navchoice = document.linkitems.toplink[document.linkitems.toplink.selectedIndex].value; |
|
ENDBLOCK |
|
foreach my $link (@linkorder) { |
|
$result.= "if (navchoice == '$link') {". |
|
$linkitems->{$link}{'cmd'}."}\n"; |
|
} |
|
$result.='} |
|
</script> |
|
<form name="linkitems" method="post"> |
|
<span class="LC_nobreak"><select name="toplink">'."\n"; |
|
foreach my $link (@linkorder) { |
foreach my $link (@linkorder) { |
if (defined($linkitems->{$link})) { |
my $link_id = 'LC_content_toolbar_'.$link; |
if ($linkitems->{$link}{'text'} ne '') { |
if (defined($linkitems->{$link})) { |
$result .= ' <option value="'.$link.'">'. |
if ($linkitems->{$link}{'text'} ne '') { |
$linkitems->{$link}{'text'}."</option>\n"; |
$linkitems->{$link}{'cmd'}=~s/"/'/g; |
} |
if ($linkitems->{$link}{'cmd'}) { |
} |
if ($link eq 'changefolder') { |
|
if ($condition) { |
|
$link_id='LC_content_toolbar_changefolder_toggled'; |
|
} else { |
|
$link_id='LC_content_toolbar_changefolder'; |
|
} |
|
} |
|
$result .= '<li><a href="#" '. |
|
'onclick="'.$linkitems->{$link}{'cmd'}.'" '. |
|
'id="'.$link_id.'" '. |
|
'class="LC_toolbarItem" '. |
|
'title="'.$linkitems->{$link}{'text'}.'">'. |
|
'</a></li>'."\n"; |
|
} |
|
} |
|
} |
} |
} |
$result .= '</select> <input type="button" name="chgnav" |
$result .= '</ul>'. |
value="Go" onClick="javascript:changeNavDisplay()" /> |
'</span></td>'."\n"; |
</span></form></td>'."\n"; |
|
|
|
return $result; |
return $result; |
} |
} |
|
|
|
|
1; |
1; |
|
|
|
|
Line 1933 sub new {
|
Line 1975 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 |
|
|
|
$self->{USERNAME} = shift || $env{'user.name'}; |
|
$self->{DOMAIN} = shift || $env{'user.domain'}; |
|
|
|
|
|
|
# Resource cache stores navmap resources as we reference them. We generate |
# Resource cache stores navmap resources as we reference them. We generate |
# them on-demand so we don't pay for creating resources unless we use them. |
# them on-demand so we don't pay for creating resources unless we use them. |
Line 1942 sub new {
|
Line 1990 sub new {
|
# failed |
# failed |
$self->{NETWORK_FAILURE} = 0; |
$self->{NETWORK_FAILURE} = 0; |
|
|
# tie the nav hash |
# 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 |
|
# assume there are course hashes for the specific requested user@domamin: |
|
# |
|
|
my %navmaphash; |
if (($self->{USERNAME} eq $env{'user.name'}) && ($self->{DOMAIN} eq $env{'user.domain'})) { |
my %parmhash; |
|
my $courseFn = $env{"request.course.fn"}; |
# tie the nav hash |
if (!(tie(%navmaphash, 'GDBM_File', "${courseFn}.db", |
|
&GDBM_READER(), 0640))) { |
my %navmaphash; |
return undef; |
my %parmhash; |
|
my $courseFn = $env{"request.course.fn"}; |
|
if (!(tie(%navmaphash, 'GDBM_File', "${courseFn}.db", |
|
&GDBM_READER(), 0640))) { |
|
return undef; |
|
} |
|
|
|
if (!(tie(%parmhash, 'GDBM_File', "${courseFn}_parms.db", |
|
&GDBM_READER(), 0640))) |
|
{ |
|
untie %{$self->{PARM_HASH}}; |
|
return undef; |
|
} |
|
|
|
$self->{NAV_HASH} = \%navmaphash; |
|
$self->{PARM_HASH} = \%parmhash; |
|
$self->{PARM_CACHE} = {}; |
|
} else { |
|
$self->change_user($self->{USERNAME}, $self->{DOMAIN}); |
} |
} |
|
|
|
return $self; |
|
} |
|
|
|
# |
|
# In some instances it is useful to be able to dynamically change the |
|
# username/domain associated with a navmap (e.g. to navigate for someone |
|
# else besides the current user...if sufficiently privileged. |
|
# Parameters: |
|
# user - New user. |
|
# domain- Domain the user belongs to. |
|
# Implicit inputs: |
|
# |
|
sub change_user { |
|
my $self = shift; |
|
$self->{USERNAME} = shift; |
|
$self->{DOMAIN} = shift; |
|
|
|
# If the hashes are already tied make sure to break that bond: |
|
|
|
untie %{$self->{NAV_HASH}}; |
|
untie %{$self->{PARM_HASH}}; |
|
|
|
# The assumption is that we have to |
|
# use lonmap here to re-read the hash and from it reconstruct |
|
# new big and parameter hashes. An implicit assumption at this time |
|
# is that the course file is probably not created locally yet |
|
# an that we will therefore just read without tying. |
|
|
|
my ($cdom, $cnum) = split(/\_/, $env{'request.course.id'}); |
|
|
|
my %big_hash; |
|
&Apache::lonmap::loadmap($cnum, $cdom, $self->{USERNAME}, $self->{DOMAIN}, \%big_hash); |
|
$self->{NAV_HASH} = \%big_hash; |
|
|
|
# Now clear the parm cache and reconstruct the parm hash fromt he big_hash |
|
# param.xxxx keys. |
|
|
|
$self->{PARM_CACHE} = {}; |
|
|
if (!(tie(%parmhash, 'GDBM_File', "${courseFn}_parms.db", |
my %parm_hash = {}; |
&GDBM_READER(), 0640))) |
foreach my $key (keys %big_hash) { |
{ |
if ($key =~ /^param\./) { |
untie %{$self->{PARM_HASH}}; |
my $param_key = $key; |
return undef; |
$param_key =~ s/^param\.//; |
|
$parm_hash{$param_key} = $big_hash{$key}; |
|
} |
} |
} |
|
|
$self->{NAV_HASH} = \%navmaphash; |
$self->{PARM_HASH} = \%parm_hash; |
$self->{PARM_HASH} = \%parmhash; |
|
$self->{PARM_CACHE} = {}; |
|
|
|
bless($self); |
|
|
|
return $self; |
} |
} |
|
|
|
sub generate_course_user_opt { |
sub generate_course_user_opt { |
my $self = shift; |
my $self = shift; |
if ($self->{COURSE_USER_OPT_GENERATED}) { return; } |
if ($self->{COURSE_USER_OPT_GENERATED}) { return; } |
|
|
my $uname=$env{'user.name'}; |
my $uname=$self->{USERNAME}; |
my $udom=$env{'user.domain'}; |
my $udom=$self->{DOMAIN}; |
|
|
my $cid=$env{'request.course.id'}; |
my $cid=$env{'request.course.id'}; |
my $cdom=$env{'course.'.$cid.'.domain'}; |
my $cdom=$env{'course.'.$cid.'.domain'}; |
my $cnum=$env{'course.'.$cid.'.num'}; |
my $cnum=$env{'course.'.$cid.'.num'}; |
Line 2016 sub generate_email_discuss_status {
|
Line 2124 sub generate_email_discuss_status {
|
my $cdom=$env{'course.'.$cid.'.domain'}; |
my $cdom=$env{'course.'.$cid.'.domain'}; |
my $cnum=$env{'course.'.$cid.'.num'}; |
my $cnum=$env{'course.'.$cid.'.num'}; |
|
|
my %emailstatus = &Apache::lonnet::dump('email_status'); |
my %emailstatus = &Apache::lonnet::dump('email_status',$self->{DOMAIN},$self->{USERNAME}); |
my $logoutTime = $emailstatus{'logout'}; |
my $logoutTime = $emailstatus{'logout'}; |
my $courseLeaveTime = $emailstatus{'logout_'.$env{'request.course.id'}}; |
my $courseLeaveTime = $emailstatus{'logout_'.$env{'request.course.id'}}; |
$self->{LAST_CHECK} = (($courseLeaveTime > $logoutTime) ? |
$self->{LAST_CHECK} = (($courseLeaveTime > $logoutTime) ? |
Line 2024 sub generate_email_discuss_status {
|
Line 2132 sub generate_email_discuss_status {
|
my %discussiontime = &Apache::lonnet::dump('discussiontimes', |
my %discussiontime = &Apache::lonnet::dump('discussiontimes', |
$cdom, $cnum); |
$cdom, $cnum); |
my %lastread = &Apache::lonnet::dump('nohist_'.$cid.'_discuss', |
my %lastread = &Apache::lonnet::dump('nohist_'.$cid.'_discuss', |
$env{'user.domain'},$env{'user.name'},'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; |
Line 2034 sub generate_email_discuss_status {
|
Line 2142 sub generate_email_discuss_status {
|
|
|
my %feedback=(); |
my %feedback=(); |
my %error=(); |
my %error=(); |
my @keys = &Apache::lonnet::getkeys('nohist_email',$env{'user.domain'}, |
my @keys = &Apache::lonnet::getkeys('nohist_email',$self->{DOMAIN}, |
$env{'user.name'}); |
$self->{USERNAME}); |
|
|
foreach my $msgid (@keys) { |
foreach my $msgid (@keys) { |
if ((!$emailstatus{$msgid}) || ($emailstatus{$msgid} eq 'new')) { |
if ((!$emailstatus{$msgid}) || ($emailstatus{$msgid} eq 'new')) { |
Line 2083 sub get_user_data {
|
Line 2191 sub get_user_data {
|
|
|
# Retrieve performance data on problems |
# Retrieve performance data on problems |
my %student_data = Apache::lonnet::currentdump($env{'request.course.id'}, |
my %student_data = Apache::lonnet::currentdump($env{'request.course.id'}, |
$env{'user.domain'}, |
$self->{DOMAIN}, |
$env{'user.name'}); |
$self->{USERNAME}); |
$self->{STUDENT_DATA} = \%student_data; |
$self->{STUDENT_DATA} = \%student_data; |
|
|
$self->{RETRIEVED_USER_DATA} = 1; |
$self->{RETRIEVED_USER_DATA} = 1; |
Line 2313 resource object.
|
Line 2421 resource object.
|
Based on the symb of the resource, get a resource object for that |
Based on the symb of the resource, get a resource object for that |
resource. This is one of the proper ways to get a resource object. |
resource. This is one of the proper ways to get a resource object. |
|
|
=item * B<getMapByMapPc>(map_pc): |
=item * B<getByMapPc>(map_pc): |
|
|
Based on the map_pc of the resource, get a resource object for |
Based on the map_pc of the resource, get a resource object for |
the given map. This is one of the proper ways to get a resource object. |
the given map. This is one of the proper ways to get a resource object. |
Line 2398 sub parmval {
|
Line 2506 sub parmval {
|
my $self = shift; |
my $self = shift; |
my ($what,$symb,$recurse)=@_; |
my ($what,$symb,$recurse)=@_; |
my $hashkey = $what."|||".$symb; |
my $hashkey = $what."|||".$symb; |
|
my $cache = $self->{PARM_CACHE}; |
if (defined($self->{PARM_CACHE}->{$hashkey})) { |
if (defined($self->{PARM_CACHE}->{$hashkey})) { |
if (ref($self->{PARM_CACHE}->{$hashkey}) eq 'ARRAY') { |
if (ref($self->{PARM_CACHE}->{$hashkey}) eq 'ARRAY') { |
if (defined($self->{PARM_CACHE}->{$hashkey}->[0])) { |
if (defined($self->{PARM_CACHE}->{$hashkey}->[0])) { |
Line 2435 sub parmval_real {
|
Line 2543 sub parmval_real {
|
@cgrps = sort(@cgrps); |
@cgrps = sort(@cgrps); |
$cgroup = $cgrps[0]; |
$cgroup = $cgrps[0]; |
} |
} |
my $uname=$env{'user.name'}; |
my $uname=$self->{USERNAME}; |
my $udom=$env{'user.domain'}; |
my $udom=$self->{DOMAIN}; |
|
|
unless ($symb) { return ['']; } |
unless ($symb) { return ['']; } |
my $result=''; |
my $result=''; |
Line 2583 in the filter function.
|
Line 2691 in the filter function.
|
Retrieves version infomation for a url. Returns the version (a number, or |
Retrieves version infomation for a url. Returns the version (a number, or |
the string "mostrecent") for resources which have version information in |
the string "mostrecent") for resources which have version information in |
the big hash. |
the big hash. |
|
|
=cut |
=cut |
|
|
|
|
Line 2838 sub new {
|
Line 2946 sub new {
|
weaken($self->{NAV_MAP} = shift); |
weaken($self->{NAV_MAP} = shift); |
return undef unless ($self->{NAV_MAP}); |
return undef unless ($self->{NAV_MAP}); |
|
|
|
$self->{USERNAME} = $self->{NAV_MAP}->{USERNAME}; |
|
$self->{DOMAIN} = $self->{NAV_MAP}->{DOMAIN}; |
|
|
# Handle the parameters |
# Handle the parameters |
$self->{FIRST_RESOURCE} = shift || $self->{NAV_MAP}->firstResource(); |
$self->{FIRST_RESOURCE} = shift || $self->{NAV_MAP}->firstResource(); |
$self->{FINISH_RESOURCE} = shift || $self->{NAV_MAP}->finishResource(); |
$self->{FINISH_RESOURCE} = shift || $self->{NAV_MAP}->finishResource(); |
Line 3211 sub new {
|
Line 3322 sub new {
|
weaken($self->{NAV_MAP} = shift); |
weaken($self->{NAV_MAP} = shift); |
return undef unless ($self->{NAV_MAP}); |
return undef unless ($self->{NAV_MAP}); |
|
|
|
$self->{USERNAME} = $self->{NAV_MAP}->{USERNAME}; |
|
$self->{DOMAIN} = $self->{NAV_MAP}->{DOMAIN}; |
|
|
$self->{FIRST_RESOURCE} = shift || $self->{NAV_MAP}->firstResource(); |
$self->{FIRST_RESOURCE} = shift || $self->{NAV_MAP}->firstResource(); |
$self->{FINISH_RESOURCE} = shift || $self->{NAV_MAP}->finishResource(); |
$self->{FINISH_RESOURCE} = shift || $self->{NAV_MAP}->finishResource(); |
|
|
Line 3447 sub new {
|
Line 3561 sub new {
|
weaken($self->{NAV_MAP} = shift); |
weaken($self->{NAV_MAP} = shift); |
$self->{ID} = shift; |
$self->{ID} = shift; |
|
|
|
$self->{USERNAME} = $self->{NAV_MAP}->{USERNAME}; |
|
$self->{DOMAIN} = $self->{NAV_MAP}->{DOMAIN}; |
|
|
# Store this new resource in the parent nav map's cache. |
# Store this new resource in the parent nav map's cache. |
$self->{NAV_MAP}->{RESOURCE_CACHE}->{$self->{ID}} = $self; |
$self->{NAV_MAP}->{RESOURCE_CACHE}->{$self->{ID}} = $self; |
$self->{RESOURCE_ERROR} = 0; |
$self->{RESOURCE_ERROR} = 0; |
Line 3468 sub navHash {
|
Line 3585 sub navHash {
|
my $self = shift; |
my $self = shift; |
my $param = shift; |
my $param = shift; |
my $id = shift; |
my $id = shift; |
return $self->{NAV_MAP}->navhash($param . ($id?$self->{ID}:"")); |
my $arg = $param . ($id?$self->{ID}:""); |
|
if (ref($self) && ref($self->{NAV_MAP}) && defined($arg)) { |
|
return $self->{NAV_MAP}->navhash($arg); |
|
} |
|
return; |
} |
} |
|
|
=pod |
=pod |
Line 3706 sub is_practice {
|
Line 3827 sub is_practice {
|
sub is_problem { |
sub is_problem { |
my $self=shift; |
my $self=shift; |
my $src = $self->src(); |
my $src = $self->src(); |
if ($src =~ /\.(problem|exam|quiz|assess|survey|form|library|task)$/) { |
if ($src =~ /$LONCAPA::assess_re/) { |
return !($self->is_practice()); |
return !($self->is_practice()); |
} |
} |
return 0; |
return 0; |
} |
} |
|
# |
|
# The has below is the set of status that are considered 'incomplete' |
|
# |
|
my %incomplete_hash = |
|
( |
|
TRIES_LEFT() => 1, |
|
OPEN() => 1, |
|
ATTEMPTED() => 1 |
|
|
|
); |
|
# |
|
# Return tru if a problem is incomplete... for now incomplete means that |
|
# any part of the problem is incomplete. |
|
# Note that if the resources is not a problem, 0 is returned. |
|
# |
|
sub is_incomplete { |
|
my $self = shift; |
|
if ($self->is_problem()) { |
|
foreach my $part (@{$self->parts()}) { |
|
if (exists($incomplete_hash{$self->status($part)})) { |
|
return 1; |
|
} |
|
} |
|
} |
|
return 0; |
|
|
|
} |
sub is_raw_problem { |
sub is_raw_problem { |
my $self=shift; |
my $self=shift; |
my $src = $self->src(); |
my $src = $self->src(); |
if ($src =~ /\.(problem|exam|quiz|assess|survey|form|library|task)$/) { |
if ($src =~ /$LONCAPA::assess_re/) { |
return 1; |
return 1; |
} |
} |
return 0; |
return 0; |
Line 3746 sub is_survey {
|
Line 3894 sub is_survey {
|
my $self = shift(); |
my $self = shift(); |
my $part = shift(); |
my $part = shift(); |
my $type = $self->parmval('type',$part); |
my $type = $self->parmval('type',$part); |
if ($type eq 'survey') { |
if (($type eq 'survey') || ($type eq 'surveycred')) { |
return 1; |
return 1; |
} |
} |
if ($self->src() =~ /\.(survey)$/) { |
if ($self->src() =~ /\.(survey)$/) { |
Line 3754 sub is_survey {
|
Line 3902 sub is_survey {
|
} |
} |
return 0; |
return 0; |
} |
} |
|
sub is_anonsurvey { |
|
my $self = shift(); |
|
my $part = shift(); |
|
my $type = $self->parmval('type',$part); |
|
if (($type eq 'anonsurvey') || ($type eq 'anonsurveycred')) { |
|
return 1; |
|
} |
|
return 0; |
|
} |
sub is_task { |
sub is_task { |
my $self=shift; |
my $self=shift; |
my $src = $self->src(); |
my $src = $self->src(); |
Line 3807 resource of the map.
|
Line 3964 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>: |
|
|
|
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 |
|
map first, then descending to deeper levels, with the enclosing map last. |
|
|
=back |
=back |
|
|
=cut |
=cut |
Line 3837 sub map_type {
|
Line 4000 sub map_type {
|
my $pc = $self->map_pc(); |
my $pc = $self->map_pc(); |
return $self->navHash("map_type_$pc", 0); |
return $self->navHash("map_type_$pc", 0); |
} |
} |
|
sub map_hierarchy { |
|
my $self = shift; |
|
my $pc = $self->map_pc(); |
|
return $self->navHash("map_hierarchy_$pc", 0); |
|
} |
|
|
##### |
##### |
# Property queries |
# Property queries |
Line 3867 their code.)
|
Line 4035 their code.)
|
|
|
=over 4 |
=over 4 |
|
|
=item * B<acc>: |
=item * B<printable> |
|
|
|
returns true if the current date is such that the |
|
specified resource part is printable. |
|
|
|
=item * B<resprintable> |
|
|
|
Returns true if all parts in the resource are printable making the |
|
entire resource printable. |
|
|
|
=item * B<acc> |
|
|
Get the Client IP/Name Access Control information. |
Get the Client IP/Name Access Control information. |
|
|
Line 3920 Get the weight for the problem.
|
Line 4098 Get the weight for the problem.
|
|
|
=cut |
=cut |
|
|
|
sub printable { |
|
|
|
my ($self, $part) = @_; |
|
|
|
# Get the print open/close dates for the resource. |
|
|
|
my $start = $self->parmval("prinstartdate", $part); |
|
my $end = $self->parmval("printenddate", $part); |
|
|
|
# The following cases apply: |
|
# - No dates set: Printable. |
|
# - Start date set but no end date: Printable if now >= start date. |
|
# - End date set but no start date: Printable if now <= end date. |
|
# - both defined: printable if start <= now <= end |
|
# |
|
my $now = time(); |
|
|
|
my $startok = 1; |
|
my $endok = 1; |
|
|
|
if ((defined $start) && ($start ne '')) { |
|
$startok = $start <= $now; |
|
} |
|
if ((defined $end) && ($end != '')) { |
|
$endok = $end >= $now; |
|
} |
|
return $startok && $endok; |
|
} |
|
|
|
sub resprintable { |
|
my $self = shift; |
|
|
|
# get parts...or realize there are no parts. |
|
|
|
my $partsref = $self->parts(); |
|
my @parts = @$partsref; |
|
|
|
if ((!defined(@parts)) || (scalar(@parts) == 0)) { |
|
return $self->printable(0); |
|
} else { |
|
foreach my $part (@parts) { |
|
if (!$self->printable($part)) { |
|
return 0; |
|
} |
|
} |
|
return 1; |
|
} |
|
} |
|
|
sub acc { |
sub acc { |
(my $self, my $part) = @_; |
(my $self, my $part) = @_; |
my $acc = $self->parmval("acc", $part); |
my $acc = $self->parmval("acc", $part); |
Line 3942 sub awarded {
|
Line 4169 sub awarded {
|
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 { |
|
my $self = shift; my $part = shift; |
|
$self->{NAV_MAP}->get_user_data(); |
|
if (!defined($part)) { $part = '0'; } |
|
return $self->{NAV_MAP}->{STUDENT_DATA}->{$self->symb()}->{'resource.'.$part.'.version'}; |
|
} |
|
sub taskstatus { |
|
my $self = shift; my $part = shift; |
|
$self->{NAV_MAP}->get_user_data(); |
|
if (!defined($part)) { $part = '0'; } |
|
return $self->{NAV_MAP}->{STUDENT_DATA}->{$self->symb()}->{'resource.'.$self->taskversion($part).'.'.$part.'.status'}; |
|
} |
|
sub solved { |
|
my $self = shift; my $part = shift; |
|
$self->{NAV_MAP}->get_user_data(); |
|
if (!defined($part)) { $part = '0'; } |
|
return $self->{NAV_MAP}->{STUDENT_DATA}->{$self->symb()}->{'resource.'.$part.'.solved'}; |
|
} |
|
sub checkedin { |
|
my $self = shift; my $part = shift; |
|
$self->{NAV_MAP}->get_user_data(); |
|
if (!defined($part)) { $part = '0'; } |
|
if ($self->is_task()) { |
|
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'}); |
|
} else { |
|
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 |
|
# Why is there a copy in lonhomework? Why not centralized? |
|
# |
|
# TODO: Centralize duedate. |
|
# |
|
|
sub duedate { |
sub duedate { |
(my $self, my $part) = @_; |
(my $self, my $part) = @_; |
my $date; |
my $date; |
Line 4022 sub weight {
|
Line 4283 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(), $env{'user.domain'}, |
$self->symb(), $self->{DOMAIN}, |
$env{'user.name'}, |
$self->{USERNAME}, |
$env{'request.course.sec'}); |
$env{'request.course.sec'}); |
return $weight; |
return $weight; |
} |
} |
Line 4037 sub part_display {
|
Line 4298 sub part_display {
|
} |
} |
return $display; |
return $display; |
} |
} |
|
sub slot_control { |
|
my $self=shift(); my $part = shift(); |
|
if (!defined($part)) { $part = '0'; } |
|
my $useslots = $self->parmval("useslots", $part); |
|
my $availablestudent = $self->parmval("availablestudent", $part); |
|
my $available = $self->parmval("available", $part); |
|
return ($useslots,$availablestudent,$available); |
|
} |
|
|
# 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()); |
my %tmpHash = &Apache::lonnet::restore($self->symb(),undef,$self->{DOMAIN},$self->{USERNAME}); |
$self->{RETURN_HASH} = \%tmpHash; |
$self->{RETURN_HASH} = \%tmpHash; |
} |
} |
} |
} |
Line 4469 sub OPEN { return 1; }
|
Line 4738 sub OPEN { return 1; }
|
sub PAST_DUE_NO_ANSWER { return 2; } |
sub PAST_DUE_NO_ANSWER { return 2; } |
sub PAST_DUE_ANSWER_LATER { return 3; } |
sub PAST_DUE_ANSWER_LATER { return 3; } |
sub ANSWER_OPEN { return 4; } |
sub ANSWER_OPEN { return 4; } |
sub NOTHING_SET { return 5; } |
sub NOTHING_SET { return 5; } |
sub NETWORK_FAILURE { return 100; } |
sub NETWORK_FAILURE { return 100; } |
|
|
# getDateStatus gets the date status for a given problem part. |
# getDateStatus gets the date status for a given problem part. |
Line 4555 Information not available due to network
|
Line 4824 Information not available due to network
|
|
|
Attempted, and not yet graded. |
Attempted, and not yet graded. |
|
|
|
=item * B<CREDIT_ATTEMPTED>: |
|
|
|
Attempted, and credit received for attempt (survey and anonymous survey only). |
|
|
=back |
=back |
|
|
=cut |
=cut |
Line 4566 sub CORRECT { return 13; }
|
Line 4839 sub CORRECT { return 13; }
|
sub CORRECT_BY_OVERRIDE { return 14; } |
sub CORRECT_BY_OVERRIDE { return 14; } |
sub EXCUSED { return 15; } |
sub EXCUSED { return 15; } |
sub ATTEMPTED { return 16; } |
sub ATTEMPTED { return 16; } |
|
sub CREDIT_ATTEMPTED { return 17; } |
|
|
sub getCompletionStatus { |
sub getCompletionStatus { |
my $self = shift; |
my $self = shift; |
Line 4584 sub getCompletionStatus {
|
Line 4858 sub getCompletionStatus {
|
if ($status eq 'incorrect_by_override') {return $self->INCORRECT_BY_OVERRIDE; } |
if ($status eq 'incorrect_by_override') {return $self->INCORRECT_BY_OVERRIDE; } |
if ($status eq 'excused') {return $self->EXCUSED; } |
if ($status eq 'excused') {return $self->EXCUSED; } |
if ($status eq 'ungraded_attempted') {return $self->ATTEMPTED; } |
if ($status eq 'ungraded_attempted') {return $self->ATTEMPTED; } |
|
if ($status eq 'credit_attempted') { |
|
if ($self->is_anonsurvey($part) || $self->is_survey($part)) { |
|
return $self->CREDIT_ATTEMPTED; |
|
} else { |
|
return $self->ATTEMPTED; |
|
} |
|
} |
return $self->NOT_ATTEMPTED; |
return $self->NOT_ATTEMPTED; |
} |
} |
|
|
Line 4673 The item is open and not yet tried.
|
Line 4954 The item is open and not yet tried.
|
|
|
The problem has been attempted. |
The problem has been attempted. |
|
|
|
=item * B<CREDIT_ATTEMPTED>: |
|
|
|
The problem has been attempted, and credit given for the attempt (survey and anonymous survey only). |
|
|
=item * B<ANSWER_SUBMITTED>: |
=item * B<ANSWER_SUBMITTED>: |
|
|
An answer has been submitted, but the student should not see it. |
An answer has been submitted, but the student should not see it. |
Line 4681 An answer has been submitted, but the st
|
Line 4966 An answer has been submitted, but the st
|
|
|
=cut |
=cut |
|
|
sub TRIES_LEFT { return 20; } |
sub TRIES_LEFT { return 20; } |
sub ANSWER_SUBMITTED { return 21; } |
sub ANSWER_SUBMITTED { return 21; } |
sub PARTIALLY_CORRECT{ return 22; } |
sub PARTIALLY_CORRECT { return 22; } |
|
|
|
sub RESERVED_LATER { return 30; } |
|
sub RESERVED { return 31; } |
|
sub RESERVED_LOCATION { return 32; } |
|
sub RESERVABLE { return 33; } |
|
sub RESERVABLE_LATER { return 34; } |
|
sub NOTRESERVABLE { return 35; } |
|
sub NOT_IN_A_SLOT { return 36; } |
|
sub NEEDS_CHECKIN { return 37; } |
|
sub WAITING_FOR_GRADE { return 38; } |
|
sub UNKNOWN { return 39; } |
|
|
sub status { |
sub status { |
my $self = shift; |
my $self = shift; |
Line 4735 sub status {
|
Line 5031 sub status {
|
return ATTEMPTED; |
return ATTEMPTED; |
} |
} |
|
|
|
if ($completionStatus == CREDIT_ATTEMPTED) { |
|
return CREDIT_ATTEMPTED; |
|
} |
|
|
# If it's EXCUSED, then return that no matter what |
# If it's EXCUSED, then return that no matter what |
if ($completionStatus == EXCUSED) { |
if ($completionStatus == EXCUSED) { |
return EXCUSED; |
return EXCUSED; |
Line 4776 sub status {
|
Line 5076 sub status {
|
return OPEN; |
return OPEN; |
} |
} |
|
|
|
sub check_for_slot { |
|
my $self = shift; |
|
my $part = shift; |
|
my ($use_slots,$available,$availablestudent) = $self->slot_control($part); |
|
if (($use_slots ne '') && ($use_slots !~ /^\s*no\s*$/i)) { |
|
my @slots = (split(/:/,$availablestudent),split(/:/,$available)); |
|
my $cid=$env{'request.course.id'}; |
|
my $cdom=$env{'course.'.$cid.'.domain'}; |
|
my $cnum=$env{'course.'.$cid.'.num'}; |
|
my $now = time; |
|
if (@slots > 0) { |
|
my %slots=&Apache::lonnet::get('slots',[@slots],$cdom,$cnum); |
|
if (&Apache::lonnet::error(%slots)) { |
|
return (UNKNOWN); |
|
} |
|
my @sorted_slots = &Apache::loncommon::sorted_slots(\@slots,\%slots); |
|
my ($checkedin,$checkedinslot); |
|
foreach my $slot_name (@sorted_slots) { |
|
next if (!defined($slots{$slot_name}) || |
|
!ref($slots{$slot_name})); |
|
my $end = $slots{$slot_name}->{'endtime'}; |
|
my $start = $slots{$slot_name}->{'starttime'}; |
|
my $ip = $slots{$slot_name}->{'ip'}; |
|
if ($self->simpleStatus() == OPEN) { |
|
my $startreserve = $slots{$slot_name}->{'startreserve'}; |
|
my @proctors; |
|
if ($slots{$slot_name}->{'proctor'} ne '') { |
|
@proctors = split(',',$slots{$slot_name}->{'proctor'}); |
|
} |
|
if ($end > $now) { |
|
($checkedin,$checkedinslot) = $self->checkedin(); |
|
if ($startreserve < $now) { |
|
if ($start > $now) { |
|
return (RESERVED_LATER,$start,$slot_name); |
|
} else { |
|
if ($ip ne '') { |
|
if (!&Apache::loncommon::check_ip_acc($ip)) { |
|
return (RESERVED_LOCATION,$ip,$slot_name); |
|
} |
|
} |
|
if (@proctors > 0) { |
|
unless ((grep(/^\Q$checkedin\E/,@proctors)) && |
|
($checkedinslot eq $slot_name)) { |
|
return (NEEDS_CHECKIN,undef,$slot_name); |
|
} |
|
} |
|
return (RESERVED,$end,$slot_name); |
|
} |
|
} else { |
|
if ($start > $now) { |
|
return (RESERVABLE,$startreserve,$slot_name); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
my ($is_correct,$got_grade); |
|
if ($self->is_task()) { |
|
my $taskstatus = $self->taskstatus(); |
|
$is_correct = (($taskstatus eq 'pass') || |
|
($self->solved() =~ /^correct_/)); |
|
$got_grade = ($taskstatus =~ /^(?:pass|fail)$/); |
|
} else { |
|
$got_grade = 1; |
|
$is_correct = ($self->solved() =~ /^correct_/); |
|
} |
|
($checkedin,$checkedinslot) = $self->checkedin(); |
|
if ($checkedin) { |
|
if (!$got_grade) { |
|
return (WAITING_FOR_GRADE); |
|
} elsif ($is_correct) { |
|
return (CORRECT); |
|
} |
|
} |
|
return(NOT_IN_A_SLOT); |
|
} else { |
|
if (!$future_slots_checked) { |
|
$future_slots = &get_future_slots($cdom,$cnum,$now); |
|
$future_slots_checked = 1; |
|
} |
|
if ($future_slots) { |
|
return(NOT_IN_A_SLOT); |
|
} |
|
return(NOTRESERVABLE); |
|
} |
|
} |
|
return; |
|
} |
|
|
|
sub get_future_slots { |
|
my ($cdom,$cnum,$now) = @_; |
|
my %slots=&Apache::lonnet::dump('slots',$cdom,$cnum); |
|
my $future_slots = 0; |
|
foreach my $slot (keys(%slots)) { |
|
if (($slots{$slot}->{'starttime'} > $now) && |
|
($slots{$slot}->{'endtime'} > $now)) { |
|
$future_slots ++; |
|
} |
|
} |
|
return $future_slots; |
|
} |
|
|
sub CLOSED { return 23; } |
sub CLOSED { return 23; } |
sub ERROR { return 24; } |
sub ERROR { return 24; } |
|
|
Line 4825 my %compositeToSimple =
|
Line 5227 my %compositeToSimple =
|
INCORRECT() => INCORRECT, |
INCORRECT() => INCORRECT, |
OPEN() => OPEN, |
OPEN() => OPEN, |
ATTEMPTED() => ATTEMPTED, |
ATTEMPTED() => ATTEMPTED, |
|
CREDIT_ATTEMPTED() => CORRECT, |
ANSWER_SUBMITTED() => ATTEMPTED |
ANSWER_SUBMITTED() => ATTEMPTED |
); |
); |
|
|
Line 4899 sub completable {
|
Line 5302 sub completable {
|
# and it is not "attempted" (manually graded problem), it is |
# and it is not "attempted" (manually graded problem), it is |
# not "complete" |
# not "complete" |
if ($self->getCompletionStatus($part) == ATTEMPTED() || |
if ($self->getCompletionStatus($part) == ATTEMPTED() || |
|
$self->getCompletionStatus($part) == CREDIT_ATTEMPTED() || |
$status == ANSWER_SUBMITTED() ) { |
$status == ANSWER_SUBMITTED() ) { |
# did this part already, as well as we can |
# did this part already, as well as we can |
next; |
next; |