--- loncom/interface/loncommon.pm 2011/12/23 16:55:34 1.1046
+++ loncom/interface/loncommon.pm 2024/07/04 23:00:26 1.1075.2.167
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# a pile of common routines
#
-# $Id: loncommon.pm,v 1.1046 2011/12/23 16:55:34 raeburn Exp $
+# $Id: loncommon.pm,v 1.1075.2.167 2024/07/04 23:00:26 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -61,15 +61,27 @@ use POSIX qw(strftime mktime);
use Apache::lonmenu();
use Apache::lonenc();
use Apache::lonlocal;
-use Apache::lonnet();
use HTML::Entities;
use Apache::lonhtmlcommon();
use Apache::loncoursedata();
use Apache::lontexconvert();
use Apache::lonclonecourse();
+use Apache::lonuserutils();
+use Apache::lonuserstate();
+use Apache::courseclassifier();
use LONCAPA qw(:DEFAULT :match);
+use HTTP::Request;
use DateTime::TimeZone;
-use DateTime::Locale::Catalog;
+use DateTime::Locale;
+use Encode();
+use Authen::Captcha;
+use Captcha::reCAPTCHA;
+use JSON::DWIW;
+use LWP::UserAgent;
+use Crypt::DES;
+use DynaLoader; # for Crypt::DES version
+use File::Copy();
+use File::Path();
# ---------------------------------------------- Designs
use vars qw(%defaultdesign);
@@ -154,6 +166,8 @@ sub ssi_with_retries {
# ----------------------------------------------- Filetypes/Languages/Copyright
my %language;
my %supported_language;
+my %latex_language; # For choosing hyphenation in
+my %latex_language_bykey; # for choosing hyphenation from metadata
my %cprtag;
my %scprtag;
my %fe; my %fd; my %fm;
@@ -182,15 +196,19 @@ BEGIN {
{
my $langtabfile = $Apache::lonnet::perlvar{'lonTabDir'}.
'/language.tab';
- if ( open(my $fh,"<$langtabfile") ) {
+ if ( open(my $fh,'<',$langtabfile) ) {
while (my $line = <$fh>) {
next if ($line=~/^\#/);
chomp($line);
- my ($key,$two,$country,$three,$enc,$val,$sup)=(split(/\t/,$line));
+ my ($key,$two,$country,$three,$enc,$val,$sup,$latex)=(split(/\t/,$line));
$language{$key}=$val.' - '.$enc;
if ($sup) {
$supported_language{$key}=$sup;
}
+ if ($latex) {
+ $latex_language_bykey{$key} = $latex;
+ $latex_language{$two} = $latex;
+ }
}
close($fh);
}
@@ -199,7 +217,7 @@ BEGIN {
{
my $copyrightfile = $Apache::lonnet::perlvar{'lonIncludes'}.
'/copyright.tab';
- if ( open (my $fh,"<$copyrightfile") ) {
+ if ( open (my $fh,'<',$copyrightfile) ) {
while (my $line = <$fh>) {
next if ($line=~/^\#/);
chomp($line);
@@ -213,7 +231,7 @@ BEGIN {
{
my $sourcecopyrightfile = $Apache::lonnet::perlvar{'lonIncludes'}.
'/source_copyright.tab';
- if ( open (my $fh,"<$sourcecopyrightfile") ) {
+ if ( open (my $fh,'<',$sourcecopyrightfile) ) {
while (my $line = <$fh>) {
next if ($line =~ /^\#/);
chomp($line);
@@ -227,7 +245,7 @@ BEGIN {
# -------------------------------------------------------------- default domain designs
my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors';
my $designfile = $designdir.'/default.tab';
- if ( open (my $fh,"<$designfile") ) {
+ if ( open (my $fh,'<',$designfile) ) {
while (my $line = <$fh>) {
next if ($line =~ /^\#/);
chomp($line);
@@ -241,12 +259,12 @@ BEGIN {
{
my $categoryfile = $Apache::lonnet::perlvar{'lonTabDir'}.
'/filecategories.tab';
- if ( open (my $fh,"<$categoryfile") ) {
+ if ( open (my $fh,'<',$categoryfile) ) {
while (my $line = <$fh>) {
next if ($line =~ /^\#/);
chomp($line);
my ($extension,$category)=(split(/\s+/,$line,2));
- push @{$category_extensions{lc($category)}},$extension;
+ push(@{$category_extensions{lc($category)}},$extension);
}
close($fh);
}
@@ -256,7 +274,7 @@ BEGIN {
{
my $typesfile = $Apache::lonnet::perlvar{'lonTabDir'}.
'/filetypes.tab';
- if ( open (my $fh,"<$typesfile") ) {
+ if ( open (my $fh,'<',$typesfile) ) {
while (my $line = <$fh>) {
next if ($line =~ /^\#/);
chomp($line);
@@ -409,7 +427,7 @@ sub studentbrowser_javascript {
END
# output the initial values for the selection lists
- $result .= "\n";
+ $result .= "\n";
my @order = sort(keys(%{$hashref}));
if (ref($menuorder) eq 'ARRAY') {
@order = @{$menuorder};
@@ -1137,7 +1195,11 @@ END
$result .= " \n";
my %select2 = %{$hashref->{$firstdefault}->{'select2'}};
$result .= $middletext;
- $result .= "\n";
+ $result .= "{$firstdefault}->{'default'};
my @secondorder = sort(keys(%select2));
@@ -1197,7 +1259,11 @@ sub help_open_topic {
$topic=~s/\W/\_/g;
if (!$stayOnPage) {
- $link = "javascript:openMyModal('/adm/help/${filename}.hlp',$width,$height,'yes');";
+ if ($env{'browser.mobile'}) {
+ $link = "javascript:openMyModal('/adm/help/${filename}.hlp',$width,$height,'yes');";
+ } else {
+ $link = "javascript:void(open('/adm/help/${filename}.hlp', 'Help_for_$topic', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))";
+ }
} elsif ($stayOnPage eq 'popup') {
$link = "javascript:void(open('/adm/help/${filename}.hlp', 'Help_for_$topic', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))";
} else {
@@ -1248,7 +1314,9 @@ sub helpLatexCheatsheet {
unless ($not_author) {
$out .= ' '
.&help_open_topic('Authoring_Output_Tags',&mt('Output Tags'),$stayOnPage,undef,600)
- .' ';
+ .' '
+ .&help_open_topic('Authoring_Multilingual_Problems',&mt('Languages'),$stayOnPage,undef,600)
+ .' ';
}
$out .= ''; # End cheatsheet
return $out;
@@ -1309,34 +1377,42 @@ sub help_open_menu {
}
sub top_nav_help {
- my ($text) = @_;
+ my ($text,$linkattr) = @_;
$text = &mt($text);
- my $stay_on_page = 1;
-
- my $link = ($stay_on_page) ? "javascript:helpMenu('display')"
- : "javascript:helpMenu('open')";
- my $banner_link = &update_help_link(undef,undef,undef,undef,$stay_on_page);
-
+ my $stay_on_page;
+ unless ($env{'environment.remote'} eq 'on') {
+ $stay_on_page = 1;
+ }
+ my ($link,$banner_link);
+ unless ($env{'request.noversionuri'} =~ m{^/adm/helpmenu}) {
+ $link = ($stay_on_page) ? "javascript:helpMenu('display')"
+ : "javascript:helpMenu('open')";
+ $banner_link = &update_help_link(undef,undef,undef,undef,$stay_on_page);
+ }
my $title = &mt('Get help');
-
- return <<"END";
+ if ($link) {
+ return <<"END";
$banner_link
- $text
+$text
END
+ } else {
+ return ' '.$text.' ';
+ }
}
sub help_menu_js {
- my ($text) = @_;
+ my ($httphost) = @_;
my $stayOnPage = 1;
my $width = 620;
my $height = 600;
my $helptopic=&general_help();
- my $details_link = '/adm/help/'.$helptopic.'.hlp';
+ my $details_link = $httphost.'/adm/help/'.$helptopic.'.hlp';
my $nothing=&Apache::lonhtmlcommon::javascript_nothing();
my $start_page =
&Apache::loncommon::start_page('Help Menu', undef,
{'frameset' => 1,
'js_ready' => 1,
+ 'use_absolute' => $httphost,
'add_entries' => {
'border' => '0',
'rows' => "110,*",},});
@@ -1368,9 +1444,10 @@ function helpMenu(target) {
return;
}
function writeHelp(caller) {
- caller.document.writeln('$start_page $end_page')
- caller.document.close()
- caller.focus()
+ caller.document.writeln('$start_page\\n \\n');
+ caller.document.writeln(' \\n$end_page');
+ caller.document.close();
+ caller.focus();
}
// END LON-CAPA Internal -->
// ]]>
@@ -1678,12 +1755,246 @@ RESIZE
}
+sub colorfuleditor_js {
+ return <<"COLORFULEDIT"
+
+COLORFULEDIT
+}
+
+sub xmleditor_js {
+ return <
+
+XMLEDIT
+}
+
+sub insert_folding_button {
+ my $curDepth = $Apache::lonxml::curdepth;
+ my $lastresource = $env{'request.ambiguous'};
+
+ return " ";
+}
+
+
=pod
=head1 Excel and CSV file utility routines
-=over 4
-
=cut
###############################################################
@@ -1691,6 +2002,8 @@ RESIZE
=pod
+=over 4
+
=item * &csv_translate($text)
Translate $text to allow it to be output as a 'comma separated values'
@@ -1742,6 +2055,7 @@ Inputs: $workbook
Returns: $format, a hash reference.
+
=cut
###############################################################
@@ -1936,12 +2250,15 @@ sub multiple_select_form {
=pod
-=item * &select_form($defdom,$name,$hashref,$onchange)
+=item * &select_form($defdom,$name,$hashref,$onchange,$readonly)
Returns a string containing a form to
allow a user to select options from a ref to a hash containing:
option_name => displayed text. An optional $onchange can include
-a javascript onchange item, e.g., onchange="this.form.submit();"
+a javascript onchange item, e.g., onchange="this.form.submit();".
+An optional arg -- $readonly -- if true will cause the select form
+to be disabled, e.g., for the case where an instructor has a section-
+specific role, and is viewing/modifying parameters.
See lonrights.pm for an example invocation and use.
@@ -1949,12 +2266,16 @@ See lonrights.pm for an example invocati
#-------------------------------------------
sub select_form {
- my ($def,$name,$hashref,$onchange) = @_;
+ my ($def,$name,$hashref,$onchange,$readonly) = @_;
return unless (ref($hashref) eq 'HASH');
if ($onchange) {
$onchange = ' onchange="'.$onchange.'"';
}
- my $selectform = "\n";
+ my $disabled;
+ if ($readonly) {
+ $disabled = ' disabled="disabled"';
+ }
+ my $selectform = "\n";
my @keys;
if (exists($hashref->{'select_form_order'})) {
@keys=@{$hashref->{'select_form_order'}};
@@ -1974,19 +2295,112 @@ sub select_form {
# For display filters
sub display_filter {
+ my ($context) = @_;
if (!$env{'form.show'}) { $env{'form.show'}=10; }
if (!$env{'form.displayfilter'}) { $env{'form.displayfilter'}='currentfolder'; }
- return ''.&mt('Records [_1]',
+ my $phraseinput = 'hidden';
+ my $includeinput = 'hidden';
+ my ($checked,$includetypestext);
+ if ($env{'form.displayfilter'} eq 'containing') {
+ $phraseinput = 'text';
+ if ($context eq 'parmslog') {
+ $includeinput = 'checkbox';
+ if ($env{'form.includetypes'}) {
+ $checked = ' checked="checked"';
+ }
+ $includetypestext = &mt('Include parameter types');
+ }
+ } else {
+ $includetypestext = ' ';
+ }
+ my ($additional,$secondid,$thirdid);
+ if ($context eq 'parmslog') {
+ $additional =
+ ' '.
+ ' '.$includetypestext.' '.
+ ' ';
+ $secondid = 'includetypes';
+ $thirdid = 'includetypestext';
+ }
+ my $onchange = "javascript:toggleHistoryOptions(this,'containingphrase','$context',
+ '$secondid','$thirdid')";
+ return ''.&mt('Records: [_1]',
&Apache::lonmeta::selectbox('show',$env{'form.show'},undef,
(&mt('all'),10,20,50,100,1000,10000))).
' '.
- &mt('Filter [_1]',
+ &mt('Filter: [_1]',
&select_form($env{'form.displayfilter'},
'displayfilter',
{'currentfolder' => 'Current folder/page',
'containing' => 'Containing phrase',
- 'none' => 'None'})).
- ' ';
+ 'none' => 'None'},$onchange)).' '.
+ ' '.$additional;
+}
+
+sub display_filter_js {
+ my $includetext = &mt('Include parameter types');
+ return <<"ENDJS";
+
+function toggleHistoryOptions(setter,firstid,context,secondid,thirdid) {
+ var firstType = 'hidden';
+ if (setter.options[setter.selectedIndex].value == 'containing') {
+ firstType = 'text';
+ }
+ firstObject = document.getElementById(firstid);
+ if (typeof(firstObject) == 'object') {
+ if (firstObject.type != firstType) {
+ changeInputType(firstObject,firstType);
+ }
+ }
+ if (context == 'parmslog') {
+ var secondType = 'hidden';
+ if (firstType == 'text') {
+ secondType = 'checkbox';
+ }
+ secondObject = document.getElementById(secondid);
+ if (typeof(secondObject) == 'object') {
+ if (secondObject.type != secondType) {
+ changeInputType(secondObject,secondType);
+ }
+ }
+ var textItem = document.getElementById(thirdid);
+ var currtext = textItem.innerHTML;
+ var newtext;
+ if (firstType == 'text') {
+ newtext = '$includetext';
+ } else {
+ newtext = ' ';
+ }
+ if (currtext != newtext) {
+ textItem.innerHTML = newtext;
+ }
+ }
+ return;
+}
+
+function changeInputType(oldObject,newType) {
+ var newObject = document.createElement('input');
+ newObject.type = newType;
+ if (oldObject.size) {
+ newObject.size = oldObject.size;
+ }
+ if (oldObject.value) {
+ newObject.value = oldObject.value;
+ }
+ if (oldObject.name) {
+ newObject.name = oldObject.name;
+ }
+ if (oldObject.id) {
+ newObject.id = oldObject.id;
+ }
+ oldObject.parentNode.replaceChild(newObject,oldObject);
+ return;
+}
+
+ENDJS
}
sub gradeleveldescription {
@@ -2030,7 +2444,7 @@ sub select_level_form {
=pod
-=item * &select_dom_form($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms)
+=item * &select_dom_form($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms,$excdoms,$disabled)
Returns a string containing a form to
allow a user to select the domain to preform an operation in.
@@ -2043,25 +2457,36 @@ If the $showdomdesc flag is set, the dom
The optional $onchange argument specifies what should occur if the domain selector is changed, e.g., 'this.form.submit()' if the form is to be automatically submitted.
-The optional $incdoms is a reference to an array of domains which will be the only available options.
+The optional $incdoms is a reference to an array of domains which will be the only available options.
+
+The optional $excdoms is a reference to an array of domains which will be excluded from the available options.
+
+The optional $disabled argument, if true, adds the disabled attribute to the select tag.
=cut
#-------------------------------------------
sub select_dom_form {
- my ($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms) = @_;
+ my ($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms,$excdoms,$disabled) = @_;
if ($onchange) {
$onchange = ' onchange="'.$onchange.'"';
}
- my @domains;
+ if ($disabled) {
+ $disabled = ' disabled="disabled"';
+ }
+ my (@domains,%exclude);
if (ref($incdoms) eq 'ARRAY') {
@domains = sort {lc($a) cmp lc($b)} (@{$incdoms});
} else {
@domains = sort {lc($a) cmp lc($b)} (&Apache::lonnet::all_domains());
}
if ($includeempty) { @domains=('',@domains); }
- my $selectdomain = "\n";
+ if (ref($excdoms) eq 'ARRAY') {
+ map { $exclude{$_} = 1; } @{$excdoms};
+ }
+ my $selectdomain = "\n";
foreach my $dom (@domains) {
+ next if ($exclude{$dom});
$selectdomain.="'.$dom;
if ($showdomdesc) {
@@ -2182,6 +2607,12 @@ Outputs:
=item * $clientos
+=item * $clientmobile
+
+=item * $clientinfo
+
+=item * $clientosversion
+
=back
=back
@@ -2200,8 +2631,10 @@ sub decode_user_agent {
my $clientversion='0';
my $clientmathml='';
my $clientunicode='0';
+ my $clientmobile=0;
+ my $clientosversion='';
for (my $i=0;$i<=$#browsertype;$i++) {
- my ($bname,$match,$notmatch,$vreg,$minv,$univ)=split(/\:/,$browsertype[$i]);
+ my ($bname,$match,$notmatch,$vreg,$minv,$univ)=split(/\%/,$browsertype[$i]);
if (($httpbrowser=~/$match/i) && ($httpbrowser!~/$notmatch/i)) {
$clientbrowser=$bname;
$httpbrowser=~/$vreg/i;
@@ -2211,6 +2644,7 @@ sub decode_user_agent {
}
}
my $clientos='unknown';
+ my $clientinfo;
if (($httpbrowser=~/linux/i) ||
($httpbrowser=~/unix/i) ||
($httpbrowser=~/ux/i) ||
@@ -2220,10 +2654,24 @@ sub decode_user_agent {
if ($httpbrowser=~/next/i) { $clientos='next'; }
if (($httpbrowser=~/mac/i) ||
($httpbrowser=~/powerpc/i)) { $clientos='mac'; }
- if ($httpbrowser=~/win/i) { $clientos='win'; }
+ if ($httpbrowser=~/win/i) {
+ $clientos='win';
+ if ($httpbrowser =~/Windows\s+NT\s+(\d+\.\d+)/i) {
+ $clientosversion = $1;
+ }
+ }
if ($httpbrowser=~/embed/i) { $clientos='pda'; }
+ if ($httpbrowser=~/(Android|iPod|iPad|iPhone|webOS|Blackberry|Windows Phone|Opera m(?:ob|in)|Fennec)/i) {
+ $clientmobile=lc($1);
+ }
+ if ($httpbrowser=~ m{Firefox/(\d+\.\d+)}) {
+ $clientinfo = 'firefox-'.$1;
+ } elsif ($httpbrowser=~ m{chromeframe/(\d+\.\d+)\.}) {
+ $clientinfo = 'chromeframe-'.$1;
+ }
return ($httpbrowser,$clientbrowser,$clientversion,$clientmathml,
- $clientunicode,$clientos,);
+ $clientunicode,$clientos,$clientmobile,$clientinfo,
+ $clientosversion);
}
###############################################################
@@ -2375,7 +2823,7 @@ END
return $result;
}
-sub authform_authorwarning{
+sub authform_authorwarning {
my $result='';
$result=''.
&mt('As a general rule, only authors or co-authors should be '.
@@ -2384,16 +2832,16 @@ sub authform_authorwarning{
return $result;
}
-sub authform_nochange{
+sub authform_nochange {
my %in = (
formname => 'document.cu',
kerb_def_dom => 'MSU.EDU',
@_,
);
- my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
+ my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
my $result;
- if (keys(%can_assign) == 0) {
- $result = &mt('Under you current role you are not permitted to change login settings for this user');
+ if (!$authnum) {
+ $result = &mt('Under your current role you are not permitted to change login settings for this user');
} else {
$result = ''.&mt('[_1] Do not change login data',
' ';
+ $authtype = ' ';
}
}
}
@@ -2472,12 +2923,12 @@ sub authform_kerberos {
if ($authtype eq '') {
$authtype = ' ';
+ $krbcheck.$disabled.' />';
}
if (($can_assign{'krb4'} && $can_assign{'krb5'}) ||
- ($can_assign{'krb4'} && !$can_assign{'krb5'} &&
+ ($can_assign{'krb4'} && !$can_assign{'krb5'} &&
$in{'curr_authtype'} eq 'krb5') ||
- (!$can_assign{'krb4'} && $can_assign{'krb5'} &&
+ (!$can_assign{'krb4'} && $can_assign{'krb5'} &&
$in{'curr_authtype'} eq 'krb4')) {
$result .= &mt
('[_1] Kerberos authenticated with domain [_2] '.
@@ -2485,9 +2936,9 @@ sub authform_kerberos {
''.$authtype,
' ',
- ' ',
- ' ',
+ 'onchange="'.$jscall.'"'.$disabled.' />',
+ ' ',
+ ' ',
' ');
} elsif ($can_assign{'krb4'}) {
$result .= &mt
@@ -2496,7 +2947,7 @@ sub authform_kerberos {
''.$authtype,
' ',
+ 'onchange="'.$jscall.'"'.$disabled.' />',
' ',
' ');
} elsif ($can_assign{'krb5'}) {
@@ -2506,21 +2957,24 @@ sub authform_kerberos {
''.$authtype,
' ',
+ 'onchange="'.$jscall.'"'.$disabled.' />',
' ',
' ');
}
return $result;
}
-sub authform_internal{
+sub authform_internal {
my %in = (
formname => 'document.cu',
kerb_def_dom => 'MSU.EDU',
@_,
);
- my ($intcheck,$intarg,$result,$authtype,$autharg,$jscall);
- my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
+ my ($intcheck,$intarg,$result,$authtype,$autharg,$jscall,$disabled);
+ my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
+ if ($in{'readonly'}) {
+ $disabled = ' disabled="disabled"';
+ }
if (defined($in{'curr_authtype'})) {
if ($in{'curr_authtype'} eq 'int') {
if ($can_assign{'int'}) {
@@ -2549,7 +3003,7 @@ sub authform_internal{
if (defined($in{'mode'})) {
if ($in{'mode'} eq 'modifycourse') {
if ($authnum == 1) {
- $authtype = ' ';
+ $authtype = ' ';
}
}
}
@@ -2557,25 +3011,28 @@ sub authform_internal{
$jscall = "javascript:changed_radio('int',$in{'formname'});";
if ($authtype eq '') {
$authtype = ' ';
+ ' onchange="'.$jscall.'" onclick="'.$jscall.'"'.$disabled.' />';
}
$autharg = ' ';
+ $intarg.'" onchange="'.$jscall.'"'.$disabled.' />';
$result = &mt
('[_1] Internally authenticated (with initial password [_2])',
''.$authtype,' '.$autharg);
- $result.=" ".&mt('Visible input').' ';
+ $result.=' '.&mt('Visible input').' ';
return $result;
}
-sub authform_local{
+sub authform_local {
my %in = (
formname => 'document.cu',
kerb_def_dom => 'MSU.EDU',
@_,
);
- my ($loccheck,$locarg,$result,$authtype,$autharg,$jscall);
- my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
+ my ($loccheck,$locarg,$result,$authtype,$autharg,$jscall,$disabled);
+ my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
+ if ($in{'readonly'}) {
+ $disabled = ' disabled="disabled"';
+ }
if (defined($in{'curr_authtype'})) {
if ($in{'curr_authtype'} eq 'loc') {
if ($can_assign{'loc'}) {
@@ -2604,7 +3061,7 @@ sub authform_local{
if (defined($in{'mode'})) {
if ($in{'mode'} eq 'modifycourse') {
if ($authnum == 1) {
- $authtype = ' ';
+ $authtype = ' ';
}
}
}
@@ -2613,23 +3070,26 @@ sub authform_local{
if ($authtype eq '') {
$authtype = ' ';
+ $jscall.'"'.$disabled.' />';
}
$autharg = ' ';
+ $locarg.'" onchange="'.$jscall.'"'.$disabled.' />';
$result = &mt('[_1] Local Authentication with argument [_2]',
''.$authtype,' '.$autharg);
return $result;
}
-sub authform_filesystem{
+sub authform_filesystem {
my %in = (
formname => 'document.cu',
kerb_def_dom => 'MSU.EDU',
@_,
);
- my ($fsyscheck,$result,$authtype,$autharg,$jscall);
- my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
+ my ($fsyscheck,$result,$authtype,$autharg,$jscall,$disabled);
+ my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
+ if ($in{'readonly'}) {
+ $disabled = ' disabled="disabled"';
+ }
if (defined($in{'curr_authtype'})) {
if ($in{'curr_authtype'} eq 'fsys') {
if ($can_assign{'fsys'}) {
@@ -2655,7 +3115,7 @@ sub authform_filesystem{
if (defined($in{'mode'})) {
if ($in{'mode'} eq 'modifycourse') {
if ($authnum == 1) {
- $authtype = ' ';
+ $authtype = ' ';
}
}
}
@@ -2664,16 +3124,13 @@ sub authform_filesystem{
if ($authtype eq '') {
$authtype = ' ';
+ $jscall.'"'.$disabled.' />';
}
- $autharg = ' ';
+ $autharg = ' ';
$result = &mt
('[_1] Filesystem Authenticated (with initial password [_2])',
- ' ',
- ' ');
+ ''.$authtype,' '.$autharg);
return $result;
}
@@ -2695,7 +3152,7 @@ sub get_assignable_auth {
my $context;
if ($env{'request.role'} =~ /^au/) {
$context = 'author';
- } elsif ($env{'request.role'} =~ /^dc/) {
+ } elsif ($env{'request.role'} =~ /^(dc|dh)/) {
$context = 'domain';
} elsif ($env{'request.course.id'}) {
$context = 'course';
@@ -2719,6 +3176,79 @@ sub get_assignable_auth {
return ($authnum,%can_assign);
}
+sub check_passwd_rules {
+ my ($domain,$plainpass) = @_;
+ my %passwdconf = &Apache::lonnet::get_passwdconf($domain);
+ my ($min,$max,@chars,@brokerule,$warning);
+ $min = $Apache::lonnet::passwdmin;
+ if (ref($passwdconf{'chars'}) eq 'ARRAY') {
+ if ($passwdconf{'min'} =~ /^\d+$/) {
+ if ($passwdconf{'min'} > $min) {
+ $min = $passwdconf{'min'};
+ }
+ }
+ if ($passwdconf{'max'} =~ /^\d+$/) {
+ $max = $passwdconf{'max'};
+ }
+ @chars = @{$passwdconf{'chars'}};
+ }
+ if (($min) && (length($plainpass) < $min)) {
+ push(@brokerule,'min');
+ }
+ if (($max) && (length($plainpass) > $max)) {
+ push(@brokerule,'max');
+ }
+ if (@chars) {
+ my %rules;
+ map { $rules{$_} = 1; } @chars;
+ if ($rules{'uc'}) {
+ unless ($plainpass =~ /[A-Z]/) {
+ push(@brokerule,'uc');
+ }
+ }
+ if ($rules{'lc'}) {
+ unless ($plainpass =~ /[a-z]/) {
+ push(@brokerule,'lc');
+ }
+ }
+ if ($rules{'num'}) {
+ unless ($plainpass =~ /\d/) {
+ push(@brokerule,'num');
+ }
+ }
+ if ($rules{'spec'}) {
+ unless ($plainpass =~ /[!"#$%&'()*+,\-.\/:;<=>?@[\\\]^_`{|}~]/) {
+ push(@brokerule,'spec');
+ }
+ }
+ }
+ if (@brokerule) {
+ my %rulenames = &Apache::lonlocal::texthash(
+ uc => 'At least one upper case letter',
+ lc => 'At least one lower case letter',
+ num => 'At least one number',
+ spec => 'At least one non-alphanumeric',
+ );
+ $rulenames{'uc'} .= ': ABCDEFGHIJKLMNOPQRSTUVWXYZ';
+ $rulenames{'lc'} .= ': abcdefghijklmnopqrstuvwxyz';
+ $rulenames{'num'} .= ': 0123456789';
+ $rulenames{'spec'} .= ': !"\#$%&\'()*+,-./:;<=>?@[\]^_\`{|}~';
+ $rulenames{'min'} = &mt('Minimum password length: [_1]',$min);
+ $rulenames{'max'} = &mt('Maximum password length: [_1]',$max);
+ $warning = &mt('Password did not satisfy the following:').'';
+ foreach my $rule ('min','max','uc','lc','num','spec') {
+ if (grep(/^$rule$/,@brokerule)) {
+ $warning .= ''.$rulenames{$rule}.' ';
+ }
+ }
+ $warning .= ' ';
+ }
+ if (wantarray) {
+ return @brokerule;
+ }
+ return $warning;
+}
+
###############################################################
## Get Kerberos Defaults for Domain ##
###############################################################
@@ -2850,6 +3380,7 @@ database which holds them.
Uses global $thesaurus_db_file.
+
=cut
###############################################################
@@ -3082,7 +3613,7 @@ sub screenname {
# ------------------------------------------------------------- Confirm Wrapper
=pod
-=item confirmwrapper
+=item * &confirmwrapper($message)
Wrap messages about completion of operation in box
@@ -3121,12 +3652,12 @@ sub noteswrapper {
# ------------------------------------------------------------- Aboutme Wrapper
sub aboutmewrapper {
- my ($link,$username,$domain,$target)=@_;
+ my ($link,$username,$domain,$target,$class)=@_;
if (!defined($username) && !defined($domain)) {
return;
}
- return ''.$link.' ';
+ return ''.$link.' ';
}
# ------------------------------------------------------------ Syllabus Wrapper
@@ -3138,6 +3669,30 @@ sub syllabuswrapper {
# -----------------------------------------------------------------------------
+sub aboutme_on {
+ my ($uname,$udom)=@_;
+ unless ($uname) { $uname=$env{'user.name'}; }
+ unless ($udom) { $udom=$env{'user.domain'}; }
+ return if ($udom eq 'public' && $uname eq 'public');
+ my $hashkey=$uname.':'.$udom;
+ my ($aboutme,$cached)=&Apache::lonnet::is_cached_new('aboutme',$hashkey);
+ if ($cached) {
+ return $aboutme;
+ }
+ $aboutme = &Apache::lonnet::usertools_access($uname,$udom,'aboutme');
+ &Apache::lonnet::do_cache_new('aboutme',$hashkey,$aboutme,3600);
+ return $aboutme;
+}
+
+sub devalidate_aboutme_cache {
+ my ($uname,$udom)=@_;
+ if (!$udom) { $udom =$env{'user.domain'}; }
+ if (!$uname) { $uname=$env{'user.name'}; }
+ return if ($udom eq 'public' && $uname eq 'public');
+ my $id=$uname.':'.$udom;
+ &Apache::lonnet::devalidate_cache_new('aboutme',$id);
+}
+
sub track_student_link {
my ($linktext,$sname,$sdom,$target,$start,$only_body) = @_;
my $link ="/adm/trackstudent?";
@@ -3227,11 +3782,29 @@ sub languagedescription {
($supported_language{$code}?' ('.&mt('interface available').')':'');
}
+=pod
+
+=item * &plainlanguagedescription
+
+Returns both the plain language description (e.g. 'Creoles and Pidgins, English-based (Other)')
+and the language character encoding (e.g. ISO) separated by a ' - ' string.
+
+=cut
+
sub plainlanguagedescription {
my $code=shift;
return $language{$code};
}
+=pod
+
+=item * &supportedlanguagecode
+
+Returns the supported language code (e.g. sptutf maps to pt) given a language
+code.
+
+=cut
+
sub supportedlanguagecode {
my $code=shift;
return $supported_language{$code};
@@ -3239,6 +3812,35 @@ sub supportedlanguagecode {
=pod
+=item * &latexlanguage()
+
+Given a language key code returns the correspondnig language to use
+to select the correct hyphenation on LaTeX printouts. This is undef if there
+is no supported hyphenation for the language code.
+
+=cut
+
+sub latexlanguage {
+ my $code = shift;
+ return $latex_language{$code};
+}
+
+=pod
+
+=item * &latexhyphenation()
+
+Same as above but what's supplied is the language as it might be stored
+in the metadata.
+
+=cut
+
+sub latexhyphenation {
+ my $key = shift;
+ return $latex_language_bykey{$key};
+}
+
+=pod
+
=item * ©rightids()
returns list of all copyrights
@@ -3451,7 +4053,7 @@ sub user_lang {
=over 4
=item * &get_previous_attempt($symb, $username, $domain, $course,
- $getattempt, $regexp, $gradesub)
+ $getattempt, $regexp, $gradesub, $usec, $identifier)
Return string with previous attempt on problem. Arguments:
@@ -3473,6 +4075,11 @@ Return string with previous attempt on p
=item * $gradesub: routine that processes the string if it matches $regexp
+=item * $usec: section of the desired student
+
+=item * $identifier: counter for student (multiple students one problem) or
+ problem (one student; whole sequence).
+
=back
The output string is a table containing all desired attempts, if any.
@@ -3480,7 +4087,7 @@ The output string is a table containing
=cut
sub get_previous_attempt {
- my ($symb,$username,$domain,$course,$getattempt,$regexp,$gradesub)=@_;
+ my ($symb,$username,$domain,$course,$getattempt,$regexp,$gradesub,$usec,$identifier)=@_;
my $prevattempts='';
no strict 'refs';
if ($symb) {
@@ -3490,13 +4097,18 @@ sub get_previous_attempt {
my %lasthash=();
my $version;
for ($version=1;$version<=$returnhash{'version'};$version++) {
- foreach my $key (sort(split(/\:/,$returnhash{$version.':keys'}))) {
- $lasthash{$key}=$returnhash{$version.':'.$key};
+ foreach my $key (reverse(sort(split(/\:/,$returnhash{$version.':keys'})))) {
+ if ($key =~ /\.rawrndseed$/) {
+ my ($id) = ($key =~ /^(.+)\.rawrndseed$/);
+ $lasthash{$id.'.rndseed'} = $returnhash{$version.':'.$key};
+ } else {
+ $lasthash{$key}=$returnhash{$version.':'.$key};
+ }
}
}
$prevattempts=&start_data_table().&start_data_table_header_row();
$prevattempts.=''.&mt('History').' ';
- my (%typeparts,%lasthidden);
+ my (%typeparts,%lasthidden,%regraded,%hidestatus);
my $showsurv=&Apache::lonnet::allowed('vas',$env{'request.course.id'});
foreach my $key (sort(keys(%lasthash))) {
my ($ign,@parts) = split(/\./,$key);
@@ -3513,6 +4125,18 @@ sub get_previous_attempt {
$lasthidden{$ign.'.'.$id} = 1;
}
}
+ if ($identifier ne '') {
+ my $id = join(',',@parts);
+ if (&Apache::lonnet::EXT("resource.$id.problemstatus",$symb,
+ $domain,$username,$usec,undef,$course) =~ /^no/) {
+ $hidestatus{$ign.'.'.$id} = 1;
+ }
+ }
+ } elsif ($data eq 'regrader') {
+ if (($identifier ne '') && (@parts)) {
+ my $id = join(',',@parts);
+ $regraded{$ign.'.'.$id} = 1;
+ }
}
} else {
if ($#parts == 0) {
@@ -3524,17 +4148,60 @@ sub get_previous_attempt {
}
$prevattempts.=&end_data_table_header_row();
if ($getattempt eq '') {
+ my (%solved,%resets,%probstatus);
+ if (($identifier ne '') && (keys(%regraded) > 0)) {
+ for ($version=1;$version<=$returnhash{'version'};$version++) {
+ foreach my $id (keys(%regraded)) {
+ if (($returnhash{$version.':'.$id.'.regrader'}) &&
+ ($returnhash{$version.':'.$id.'.tries'} eq '') &&
+ ($returnhash{$version.':'.$id.'.award'} eq '')) {
+ push(@{$resets{$id}},$version);
+ }
+ }
+ }
+ }
for ($version=1;$version<=$returnhash{'version'};$version++) {
- my @hidden;
+ my (@hidden,@unsolved);
if (%typeparts) {
foreach my $id (keys(%typeparts)) {
- if (($returnhash{$version.':'.$id.'.type'} eq 'anonsurvey') || ($returnhash{$version.':'.$id.'.type'} eq 'anonsurveycred')) {
+ if (($returnhash{$version.':'.$id.'.type'} eq 'anonsurvey') ||
+ ($returnhash{$version.':'.$id.'.type'} eq 'anonsurveycred')) {
push(@hidden,$id);
+ } elsif ($identifier ne '') {
+ unless (($returnhash{$version.':'.$id.'.type'} eq 'survey') ||
+ ($returnhash{$version.':'.$id.'.type'} eq 'surveycred') ||
+ ($hidestatus{$id})) {
+ next if ((ref($resets{$id}) eq 'ARRAY') && grep(/^\Q$version\E$/,@{$resets{$id}}));
+ if ($returnhash{$version.':'.$id.'.solved'} eq 'correct_by_student') {
+ push(@{$solved{$id}},$version);
+ } elsif (($returnhash{$version.':'.$id.'.solved'} ne '') &&
+ (ref($solved{$id}) eq 'ARRAY')) {
+ my $skip;
+ if (ref($resets{$id}) eq 'ARRAY') {
+ foreach my $reset (@{$resets{$id}}) {
+ if ($reset > $solved{$id}[-1]) {
+ $skip=1;
+ last;
+ }
+ }
+ }
+ unless ($skip) {
+ my ($ign,$partslist) = split(/\./,$id,2);
+ push(@unsolved,$partslist);
+ }
+ }
+ }
}
}
}
$prevattempts.=&start_data_table_row().
- ''.&mt('Transaction [_1]',$version).' ';
+ ''.&mt('Transaction [_1]',$version);
+ if (@unsolved) {
+ $prevattempts .= ''.
+ ' '.
+ &mt('Hide').' ';
+ }
+ $prevattempts .= ' ';
if (@hidden) {
foreach my $key (sort(keys(%lasthash))) {
next if ($key =~ /\.foilorder$/);
@@ -3556,9 +4223,15 @@ sub get_previous_attempt {
}
} else {
if ($key =~ /\./) {
- my $value = &format_previous_attempt_value($key,
- $returnhash{$version.':'.$key});
- $prevattempts.=''.$value.' ';
+ my $value = $returnhash{$version.':'.$key};
+ if ($key =~ /\.rndseed$/) {
+ my ($id) = ($key =~ /^(.+)\.rndseed$/);
+ if (exists($returnhash{$version.':'.$id.'.rawrndseed'})) {
+ $value = $returnhash{$version.':'.$id.'.rawrndseed'};
+ }
+ }
+ $prevattempts.=''.&format_previous_attempt_value($key,$value).
+ ' ';
} else {
$prevattempts.=' ';
}
@@ -3567,9 +4240,15 @@ sub get_previous_attempt {
} else {
foreach my $key (sort(keys(%lasthash))) {
next if ($key =~ /\.foilorder$/);
- my $value = &format_previous_attempt_value($key,
- $returnhash{$version.':'.$key});
- $prevattempts.=''.$value.' ';
+ my $value = $returnhash{$version.':'.$key};
+ if ($key =~ /\.rndseed$/) {
+ my ($id) = ($key =~ /^(.+)\.rndseed$/);
+ if (exists($returnhash{$version.':'.$id.'.rawrndseed'})) {
+ $value = $returnhash{$version.':'.$id.'.rawrndseed'};
+ }
+ }
+ $prevattempts.=''.&format_previous_attempt_value($key,$value).
+ ' ';
}
}
$prevattempts.=&end_data_table_row();
@@ -3764,6 +4443,59 @@ sub get_student_view_with_retries {
}
}
+sub css_links {
+ my ($currsymb,$level) = @_;
+ my ($links,@symbs,%cssrefs,%httpref);
+ if ($level eq 'map') {
+ my $navmap = Apache::lonnavmaps::navmap->new();
+ if (ref($navmap)) {
+ my ($map,undef,$url)=&Apache::lonnet::decode_symb($currsymb);
+ my @resources = $navmap->retrieveResources($map,sub { $_[0]->is_problem() },0,0);
+ foreach my $res (@resources) {
+ if (ref($res) && $res->symb()) {
+ push(@symbs,$res->symb());
+ }
+ }
+ }
+ } else {
+ @symbs = ($currsymb);
+ }
+ foreach my $symb (@symbs) {
+ my $css_href = &Apache::lonnet::EXT('resource.0.cssfile',$symb);
+ if ($css_href =~ /\S/) {
+ unless ($css_href =~ m{https?://}) {
+ my $url = (&Apache::lonnet::decode_symb($symb))[-1];
+ my $proburl = &Apache::lonnet::clutter($url);
+ my ($probdir) = ($proburl =~ m{(.+)/[^/]+$});
+ unless ($css_href =~ m{^/}) {
+ $css_href = &Apache::lonnet::hreflocation($probdir,$css_href);
+ }
+ if ($css_href =~ m{^/(res|uploaded)/}) {
+ unless (($httpref{'httpref.'.$css_href}) ||
+ (&Apache::lonnet::is_on_map($css_href))) {
+ my $thisurl = $proburl;
+ if ($env{'httpref.'.$proburl}) {
+ $thisurl = $env{'httpref.'.$proburl};
+ }
+ $httpref{'httpref.'.$css_href} = $thisurl;
+ }
+ }
+ }
+ $cssrefs{$css_href} = 1;
+ }
+ }
+ if (keys(%httpref)) {
+ &Apache::lonnet::appenv(\%httpref);
+ }
+ if (keys(%cssrefs)) {
+ foreach my $css_href (keys(%cssrefs)) {
+ next unless ($css_href =~ m{^(/res/|/uploaded/|https?://)});
+ $links .= ' '."\n";
+ }
+ }
+ return $links;
+}
+
=pod
=item * &get_student_answers()
@@ -3935,9 +4667,7 @@ sub findallcourses {
$udom = $env{'user.domain'};
}
if (($uname ne $env{'user.name'}) || ($udom ne $env{'user.domain'})) {
- my $extra = &Apache::lonnet::freeze_escape({'skipcheck' => 1});
- my %roleshash = &Apache::lonnet::dump('roles',$udom,$uname,'.',undef,
- $extra);
+ my %roleshash = &Apache::lonnet::dump('roles',$udom,$uname);
if (!%roles) {
%roles = (
cc => 1,
@@ -3962,18 +4692,25 @@ sub findallcourses {
if ($tstart) {
next if ($tstart > $now);
}
- my ($cdom,$cnum,$sec,$cnumpart,$secpart,$role,$realsec);
+ my ($cdom,$cnum,$sec,$cnumpart,$secpart,$role);
(undef,$cdom,$cnumpart,$secpart) = split(/\//,$entry);
+ my $value = $trole.'/'.$cdom.'/';
if ($secpart eq '') {
($cnum,$role) = split(/_/,$cnumpart);
$sec = 'none';
- $realsec = '';
+ $value .= $cnum.'/';
} else {
$cnum = $cnumpart;
($sec,$role) = split(/_/,$secpart);
- $realsec = $sec;
+ $value .= $cnum.'/'.$sec;
+ }
+ if (ref($courses{$cdom.'_'.$cnum}{$sec}) eq 'ARRAY') {
+ unless (grep(/^\Q$value\E$/,@{$courses{$cdom.'_'.$cnum}{$sec}})) {
+ push(@{$courses{$cdom.'_'.$cnum}{$sec}},$value);
+ }
+ } else {
+ @{$courses{$cdom.'_'.$cnum}{$sec}} = ($value);
}
- $courses{$cdom.'_'.$cnum}{$sec} = $trole.'/'.$cdom.'/'.$cnum.'/'.$realsec;
}
} else {
foreach my $key (keys(%env)) {
@@ -3991,11 +4728,19 @@ sub findallcourses {
if ($now>$endtime) { $active=0; }
}
if ($active) {
+ my $value = $role.'/'.$cdom.'/'.$cnum.'/';
if ($sec eq '') {
$sec = 'none';
+ } else {
+ $value .= $sec;
+ }
+ if (ref($courses{$cdom.'_'.$cnum}{$sec}) eq 'ARRAY') {
+ unless (grep(/^\Q$value\E$/,@{$courses{$cdom.'_'.$cnum}{$sec}})) {
+ push(@{$courses{$cdom.'_'.$cnum}{$sec}},$value);
+ }
+ } else {
+ @{$courses{$cdom.'_'.$cnum}{$sec}} = ($value);
}
- $courses{$cdom.'_'.$cnum}{$sec} =
- $role.'/'.$cdom.'/'.$cnum.'/'.$sec;
}
}
}
@@ -4006,32 +4751,117 @@ sub findallcourses {
###############################################
sub blockcheck {
- my ($setters,$activity,$uname,$udom) = @_;
+ my ($setters,$activity,$clientip,$uname,$udom,$url,$is_course,$symb,$caller) = @_;
- if (!defined($udom)) {
- $udom = $env{'user.domain'};
+ unless ($activity eq 'docs') {
+ my ($has_evb,$check_ipaccess);
+ my $dom = $env{'user.domain'};
+ if ($env{'request.course.id'}) {
+ my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+ my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+ my $checkrole = "cm./$cdom/$cnum";
+ my $sec = $env{'request.course.sec'};
+ if ($sec ne '') {
+ $checkrole .= "/$sec";
+ }
+ if ((&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) &&
+ ($env{'request.role'} !~ /^st/)) {
+ $has_evb = 1;
+ }
+ unless ($has_evb) {
+ if (($activity eq 'printout') || ($activity eq 'grades') || ($activity eq 'search') ||
+ ($activity eq 'boards') || ($activity eq 'groups') || ($activity eq 'chat')) {
+ if ($udom eq $cdom) {
+ $check_ipaccess = 1;
+ }
+ }
+ }
+ } elsif (($activity eq 'com') || ($activity eq 'port') || ($activity eq 'blogs') ||
+ ($activity eq 'about') || ($activity eq 'wishlist') || ($activity eq 'passwd')) {
+ my $checkrole;
+ if ($env{'request.role.domain'} eq '') {
+ $checkrole = "cm./$env{'user.domain'}/";
+ } else {
+ $checkrole = "cm./$env{'request.role.domain'}/";
+ }
+ if (($checkrole) && (&Apache::lonnet::allowed('evb',undef,undef,$checkrole))) {
+ $has_evb = 1;
+ }
+ }
+ unless ($has_evb || $check_ipaccess) {
+ my @machinedoms = &Apache::lonnet::current_machine_domains();
+ if (($dom eq 'public') && ($activity eq 'port')) {
+ $dom = $udom;
+ }
+ if (($dom ne '') && (grep(/^\Q$dom\E$/,@machinedoms))) {
+ $check_ipaccess = 1;
+ } else {
+ my $lonhost = $Apache::lonnet::perlvar{'lonHostID'};
+ my $internet_names = &Apache::lonnet::get_internet_names($lonhost);
+ my $prim = &Apache::lonnet::domain($dom,'primary');
+ my $intdom = &Apache::lonnet::internet_dom($prim);
+ if (($intdom ne '') && (ref($internet_names) eq 'ARRAY')) {
+ if (grep(/^\Q$intdom\E$/,@{$internet_names})) {
+ $check_ipaccess = 1;
+ }
+ }
+ }
+ }
+ if ($check_ipaccess) {
+ my ($ipaccessref,$cached)=&Apache::lonnet::is_cached_new('ipaccess',$dom);
+ unless (defined($cached)) {
+ my %domconfig =
+ &Apache::lonnet::get_dom('configuration',['ipaccess'],$dom);
+ $ipaccessref = &Apache::lonnet::do_cache_new('ipaccess',$dom,$domconfig{'ipaccess'},1800);
+ }
+ if ((ref($ipaccessref) eq 'HASH') && ($clientip)) {
+ foreach my $id (keys(%{$ipaccessref})) {
+ if (ref($ipaccessref->{$id}) eq 'HASH') {
+ my $range = $ipaccessref->{$id}->{'ip'};
+ if ($range) {
+ if (&Apache::lonnet::ip_match($clientip,$range)) {
+ if (ref($ipaccessref->{$id}->{'commblocks'}) eq 'HASH') {
+ if ($ipaccessref->{$id}->{'commblocks'}->{$activity} eq 'on') {
+ return ('','','',$id,$dom);
+ last;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (($activity eq 'wishlist') || ($activity eq 'annotate')) {
+ return ();
+ }
}
- if (!defined($uname)) {
+ if (defined($udom) && defined($uname)) {
+ # If uname and udom are for a course, check for blocks in the course.
+ if (($is_course) || (&Apache::lonnet::is_course($udom,$uname))) {
+ my ($startblock,$endblock,$triggerblock) =
+ &get_blocks($setters,$activity,$udom,$uname,$url,$symb,$caller);
+ return ($startblock,$endblock,$triggerblock);
+ }
+ } else {
+ $udom = $env{'user.domain'};
$uname = $env{'user.name'};
}
- # If uname and udom are for a course, check for blocks in the course.
-
- if (&Apache::lonnet::is_course($udom,$uname)) {
- my %records = &Apache::lonnet::dump('comm_block',$udom,$uname);
- my ($startblock,$endblock)=&get_blocks($setters,$activity,$udom,$uname);
- return ($startblock,$endblock);
- }
-
my $startblock = 0;
my $endblock = 0;
- my %live_courses = &findallcourses(undef,$uname,$udom);
+ my $triggerblock = '';
+ my %live_courses;
+ unless (($activity eq 'wishlist') || ($activity eq 'annotate')) {
+ %live_courses = &findallcourses(undef,$uname,$udom);
+ }
# If uname is for a user, and activity is course-specific, i.e.,
# boards, chat or groups, check for blocking in current course only.
if (($activity eq 'boards' || $activity eq 'chat' ||
- $activity eq 'groups') && ($env{'request.course.id'})) {
+ $activity eq 'groups' || $activity eq 'printout') &&
+ ($env{'request.course.id'})) {
foreach my $key (keys(%live_courses)) {
if ($key ne $env{'request.course.id'}) {
delete($live_courses{$key});
@@ -4088,34 +4918,38 @@ sub blockcheck {
if ($otheruser) {
# Resource belongs to user other than current user.
# Assemble privs for that user, and check for 'evb' priv.
- my ($trole,$tdom,$tnum,$tsec);
- my $entry = $live_courses{$course}{$sec};
- if ($entry =~ /^cr/) {
- ($trole,$tdom,$tnum,$tsec) =
- ($entry =~ m|^(cr/$match_domain/$match_username/\w+)\./($match_domain)/($match_username)/?(\w*)$|);
- } else {
- ($trole,$tdom,$tnum,$tsec) = split(/\//,$entry);
- }
- my ($spec,$area,$trest,%allroles,%userroles);
- $area = '/'.$tdom.'/'.$tnum;
- $trest = $tnum;
- if ($tsec ne '') {
- $area .= '/'.$tsec;
- $trest .= '/'.$tsec;
- }
- $spec = $trole.'.'.$area;
- if ($trole =~ /^cr/) {
- &Apache::lonnet::custom_roleprivs(\%allroles,$trole,
- $tdom,$spec,$trest,$area);
- } else {
- &Apache::lonnet::standard_roleprivs(\%allroles,$trole,
- $tdom,$spec,$trest,$area);
- }
- my ($author,$adv) = &Apache::lonnet::set_userprivs(\%userroles,\%allroles);
- if ($userroles{'user.priv.'.$checkrole} =~ /evb\&([^\:]*)/) {
- if ($1) {
- $no_userblock = 1;
- last;
+ my (%allroles,%userroles);
+ if (ref($live_courses{$course}{$sec}) eq 'ARRAY') {
+ foreach my $entry (@{$live_courses{$course}{$sec}}) {
+ my ($trole,$tdom,$tnum,$tsec);
+ if ($entry =~ /^cr/) {
+ ($trole,$tdom,$tnum,$tsec) =
+ ($entry =~ m|^(cr/$match_domain/$match_username/\w+)\./($match_domain)/($match_username)/?(\w*)$|);
+ } else {
+ ($trole,$tdom,$tnum,$tsec) = split(/\//,$entry);
+ }
+ my ($spec,$area,$trest);
+ $area = '/'.$tdom.'/'.$tnum;
+ $trest = $tnum;
+ if ($tsec ne '') {
+ $area .= '/'.$tsec;
+ $trest .= '/'.$tsec;
+ }
+ $spec = $trole.'.'.$area;
+ if ($trole =~ /^cr/) {
+ &Apache::lonnet::custom_roleprivs(\%allroles,$trole,
+ $tdom,$spec,$trest,$area);
+ } else {
+ &Apache::lonnet::standard_roleprivs(\%allroles,$trole,
+ $tdom,$spec,$trest,$area);
+ }
+ }
+ my ($author,$adv,$rar) = &Apache::lonnet::set_userprivs(\%userroles,\%allroles);
+ if ($userroles{'user.priv.'.$checkrole} =~ /evb\&([^\:]*)/) {
+ if ($1) {
+ $no_userblock = 1;
+ last;
+ }
}
}
} else {
@@ -4132,49 +4966,154 @@ sub blockcheck {
($env{'request.role'} !~ m{^st\./\Q$cdom\E/\Q$cnum\E}));
next if ($no_userblock);
- # Retrieve blocking times and identity of locker for course
+ # Retrieve blocking times and identity of blocker for course
# of specified user, unless user has 'evb' privilege.
- my ($start,$end)=&get_blocks($setters,$activity,$cdom,$cnum);
+ my ($start,$end,$trigger) =
+ &get_blocks($setters,$activity,$cdom,$cnum,$url,$symb,$caller);
if (($start != 0) &&
(($startblock == 0) || ($startblock > $start))) {
$startblock = $start;
+ if ($trigger ne '') {
+ $triggerblock = $trigger;
+ }
}
if (($end != 0) &&
(($endblock == 0) || ($endblock < $end))) {
$endblock = $end;
+ if ($trigger ne '') {
+ $triggerblock = $trigger;
+ }
}
}
- return ($startblock,$endblock);
+ return ($startblock,$endblock,$triggerblock);
}
sub get_blocks {
- my ($setters,$activity,$cdom,$cnum) = @_;
+ my ($setters,$activity,$cdom,$cnum,$url,$symb,$caller) = @_;
my $startblock = 0;
my $endblock = 0;
+ my $triggerblock = '';
my $course = $cdom.'_'.$cnum;
$setters->{$course} = {};
$setters->{$course}{'staff'} = [];
$setters->{$course}{'times'} = [];
- my %records = &Apache::lonnet::dump('comm_block',$cdom,$cnum);
- foreach my $record (keys(%records)) {
- my ($start,$end) = ($record =~ m/^(\d+)____(\d+)$/);
- if ($start <= time && $end >= time) {
- my ($staff_name,$staff_dom,$title,$blocks) =
- &parse_block_record($records{$record});
- if ($blocks->{$activity} eq 'on') {
- push(@{$$setters{$course}{'staff'}},[$staff_name,$staff_dom]);
- push(@{$$setters{$course}{'times'}}, [$start,$end]);
- if ( ($startblock == 0) || ($startblock > $start) ) {
- $startblock = $start;
+ $setters->{$course}{'triggers'} = [];
+ my (@blockers,%triggered);
+ my $now = time;
+ my %commblocks = &Apache::lonnet::get_comm_blocks($cdom,$cnum);
+ if ($activity eq 'docs') {
+ my ($blocked,$nosymbcache,$noenccheck);
+ if (($caller eq 'blockedaccess') || ($caller eq 'blockingstatus')) {
+ $blocked = 1;
+ $nosymbcache = 1;
+ $noenccheck = 1;
+ }
+ @blockers = &Apache::lonnet::has_comm_blocking('bre',$symb,$url,$nosymbcache,$noenccheck,$blocked,\%commblocks);
+ foreach my $block (@blockers) {
+ if ($block =~ /^firstaccess____(.+)$/) {
+ my $item = $1;
+ my $type = 'map';
+ my $timersymb = $item;
+ if ($item eq 'course') {
+ $type = 'course';
+ } elsif ($item =~ /___\d+___/) {
+ $type = 'resource';
+ } else {
+ $timersymb = &Apache::lonnet::symbread($item);
}
- if ( ($endblock == 0) || ($endblock < $end) ) {
- $endblock = $end;
+ my $start = $env{'course.'.$cdom.'_'.$cnum.'.firstaccess.'.$timersymb};
+ my $end = $start + $env{'course.'.$cdom.'_'.$cnum.'.timerinterval.'.$timersymb};
+ $triggered{$block} = {
+ start => $start,
+ end => $end,
+ type => $type,
+ };
+ }
+ }
+ } else {
+ foreach my $block (keys(%commblocks)) {
+ if ($block =~ m/^(\d+)____(\d+)$/) {
+ my ($start,$end) = ($1,$2);
+ if ($start <= time && $end >= time) {
+ if (ref($commblocks{$block}) eq 'HASH') {
+ if (ref($commblocks{$block}{'blocks'}) eq 'HASH') {
+ if ($commblocks{$block}{'blocks'}{$activity} eq 'on') {
+ unless(grep(/^\Q$block\E$/,@blockers)) {
+ push(@blockers,$block);
+ }
+ }
+ }
+ }
+ }
+ } elsif ($block =~ /^firstaccess____(.+)$/) {
+ my $item = $1;
+ my $timersymb = $item;
+ my $type = 'map';
+ if ($item eq 'course') {
+ $type = 'course';
+ } elsif ($item =~ /___\d+___/) {
+ $type = 'resource';
+ } else {
+ $timersymb = &Apache::lonnet::symbread($item);
+ }
+ my $start = $env{'course.'.$cdom.'_'.$cnum.'.firstaccess.'.$timersymb};
+ my $end = $start + $env{'course.'.$cdom.'_'.$cnum.'.timerinterval.'.$timersymb};
+ if ($start && $end) {
+ if (($start <= time) && ($end >= time)) {
+ if (ref($commblocks{$block}) eq 'HASH') {
+ if (ref($commblocks{$block}{'blocks'}) eq 'HASH') {
+ if ($commblocks{$block}{'blocks'}{$activity} eq 'on') {
+ unless(grep(/^\Q$block\E$/,@blockers)) {
+ push(@blockers,$block);
+ $triggered{$block} = {
+ start => $start,
+ end => $end,
+ type => $type,
+ };
+ }
+ }
+ }
+ }
+ }
}
}
}
}
- return ($startblock,$endblock);
+ foreach my $blocker (@blockers) {
+ my ($staff_name,$staff_dom,$title,$blocks) =
+ &parse_block_record($commblocks{$blocker});
+ push(@{$$setters{$course}{'staff'}},[$staff_name,$staff_dom]);
+ my ($start,$end,$triggertype);
+ if ($blocker =~ m/^(\d+)____(\d+)$/) {
+ ($start,$end) = ($1,$2);
+ } elsif (ref($triggered{$blocker}) eq 'HASH') {
+ $start = $triggered{$blocker}{'start'};
+ $end = $triggered{$blocker}{'end'};
+ $triggertype = $triggered{$blocker}{'type'};
+ }
+ if ($start) {
+ push(@{$$setters{$course}{'times'}}, [$start,$end]);
+ if ($triggertype) {
+ push(@{$$setters{$course}{'triggers'}},$triggertype);
+ } else {
+ push(@{$$setters{$course}{'triggers'}},0);
+ }
+ if ( ($startblock == 0) || ($startblock > $start) ) {
+ $startblock = $start;
+ if ($triggertype) {
+ $triggerblock = $blocker;
+ }
+ }
+ if ( ($endblock == 0) || ($endblock < $end) ) {
+ $endblock = $end;
+ if ($triggertype) {
+ $triggerblock = $blocker;
+ }
+ }
+ }
+ }
+ return ($startblock,$endblock,$triggerblock);
}
sub parse_block_record {
@@ -4198,40 +5137,73 @@ sub parse_block_record {
}
sub blocking_status {
- my ($activity,$uname,$udom) = @_;
- my %setters;
-
- # check for active blocking
- my ($startblock,$endblock)=&blockcheck(\%setters,$activity,$uname,$udom);
+ my ($activity,$clientip,$uname,$udom,$url,$is_course,$symb,$caller) = @_;
+ my %setters;
- my $blocked = $startblock && $endblock ? 1 : 0;
-
- # caller just wants to know whether a block is active
- if (!wantarray) { return $blocked; }
-
- # build a link to a popup window containing the details
- my $querystring = "?activity=$activity";
- # $uname and $udom decide whose portfolio the user is trying to look at
- $querystring .= "&udom=$udom" if $udom;
- $querystring .= "&uname=$uname" if $uname;
-
- my $output .= <<'END_MYBLOCK';
- function openWindow(url, wdwName, w, h, toolbar,scrollbar) {
- var options = "width=" + w + ",height=" + h + ",";
- options += "resizable=yes,scrollbars="+scrollbar+",status=no,";
- options += "menubar=no,toolbar="+toolbar+",location=no,directories=no";
- var newWin = window.open(url, wdwName, options);
- newWin.focus();
+# check for active blocking
+ if ($clientip eq '') {
+ $clientip = &Apache::lonnet::get_requestor_ip();
+ }
+ my ($startblock,$endblock,$triggerblock,$by_ip,$blockdom) =
+ &blockcheck(\%setters,$activity,$clientip,$uname,$udom,$url,$is_course,$symb,$caller);
+ my $blocked = 0;
+ if (($startblock && $endblock) || ($by_ip)) {
+ $blocked = 1;
+ }
+
+# caller just wants to know whether a block is active
+ if (!wantarray) { return $blocked; }
+
+# build a link to a popup window containing the details
+ my $querystring = "?activity=$activity";
+# $uname and $udom decide whose portfolio (or information page) the user is trying to look at
+ if (($activity eq 'port') || ($activity eq 'about') || ($activity eq 'passwd')) {
+ $querystring .= "&udom=$udom" if ($udom =~ /^$match_domain$/);
+ $querystring .= "&uname=$uname" if ($uname =~ /^$match_username$/);
+ } elsif ($activity eq 'docs') {
+ my $showurl = &Apache::lonenc::check_encrypt($url);
+ $querystring .= '&url='.&HTML::Entities::encode($showurl,'\'&"<>');
+ if ($symb) {
+ my $showsymb = &Apache::lonenc::check_encrypt($symb);
+ $querystring .= '&symb='.&HTML::Entities::encode($showsymb,'\'&"<>');
+ }
}
+
+ my $output .= <<'END_MYBLOCK';
+function openWindow(url, wdwName, w, h, toolbar,scrollbar) {
+ var options = "width=" + w + ",height=" + h + ",";
+ options += "resizable=yes,scrollbars="+scrollbar+",status=no,";
+ options += "menubar=no,toolbar="+toolbar+",location=no,directories=no";
+ var newWin = window.open(url, wdwName, options);
+ newWin.focus();
+}
END_MYBLOCK
- $output = Apache::lonhtmlcommon::scripttag($output);
+ $output = Apache::lonhtmlcommon::scripttag($output);
- my $popupUrl = "/adm/blockingstatus/$querystring";
- my $text = mt('Communication Blocked');
-
- $output .= <<"END_BLOCK";
-
+ my $popupUrl = "/adm/blockingstatus/$querystring";
+ my $text = &mt('Communication Blocked');
+ my $class = 'LC_comblock';
+ if ($activity eq 'docs') {
+ $text = &mt('Content Access Blocked');
+ $class = '';
+ } elsif ($activity eq 'printout') {
+ $text = &mt('Printing Blocked');
+ } elsif ($activity eq 'passwd') {
+ $text = &mt('Password Changing Blocked');
+ } elsif ($activity eq 'grades') {
+ $text = &mt('Gradebook Blocked');
+ } elsif ($activity eq 'search') {
+ $text = &mt('Search Blocked');
+ } elsif ($activity eq 'about') {
+ $text = &mt('Access to User Information Pages Blocked');
+ } elsif ($activity eq 'wishlist') {
+ $text = &mt('Access to Stored Links Blocked');
+ } elsif ($activity eq 'annotate') {
+ $text = &mt('Access to Annotations Blocked');
+ }
+ $output .= <<"END_BLOCK";
+
@@ -4241,19 +5213,26 @@ END_MYBLOCK
END_BLOCK
- return ($blocked, $output);
+ return ($blocked, $output);
}
###############################################
sub check_ip_acc {
- my ($acc)=@_;
+ my ($acc,$clientip)=@_;
&Apache::lonxml::debug("acc is $acc");
if (!defined($acc) || $acc =~ /^\s*$/ || $acc =~/^\s*no\s*$/i) {
return 1;
}
my $allowed=0;
- my $ip=$env{'request.host'} || $ENV{'REMOTE_ADDR'};
+ my $ip;
+ if (($ENV{'REMOTE_ADDR'} eq '127.0.0.1') ||
+ ($ENV{'REMOTE_ADDR'} eq &Apache::lonnet::get_host_ip($Apache::lonnet::perlvar{'lonHostID'}))) {
+ $ip = $env{'request.host'} || $ENV{'REMOTE_ADDR'} || $clientip;
+ } else {
+ my $remote_ip = &Apache::lonnet::get_requestor_ip();
+ $ip = $remote_ip || $env{'request.host'} || $clientip;
+ }
my $name;
foreach my $pattern (split(',',$acc)) {
@@ -4349,23 +5328,39 @@ sub get_domainconf {
if (keys(%{$domconfig{'login'}})) {
foreach my $key (keys(%{$domconfig{'login'}})) {
if (ref($domconfig{'login'}{$key}) eq 'HASH') {
- if ($key eq 'loginvia') {
- if (ref($domconfig{'login'}{'loginvia'}) eq 'HASH') {
- foreach my $hostname (keys(%{$domconfig{'login'}{'loginvia'}})) {
- if (ref($domconfig{'login'}{'loginvia'}{$hostname}) eq 'HASH') {
- if ($domconfig{'login'}{'loginvia'}{$hostname}{'server'}) {
- my $server = $domconfig{'login'}{'loginvia'}{$hostname}{'server'};
- $designhash{$udom.'.login.loginvia'} = $server;
- if ($domconfig{'login'}{'loginvia'}{$hostname}{'serverpath'} eq 'custom') {
-
- $designhash{$udom.'.login.loginvia_'.$hostname} = $server.':'.$domconfig{'login'}{'loginvia'}{$hostname}{'custompath'};
- } else {
- $designhash{$udom.'.login.loginvia_'.$hostname} = $server.':'.$domconfig{'login'}{'loginvia'}{$hostname}{'serverpath'};
+ if (($key eq 'loginvia') || ($key eq 'headtag')) {
+ if (ref($domconfig{'login'}{$key}) eq 'HASH') {
+ foreach my $hostname (keys(%{$domconfig{'login'}{$key}})) {
+ if (ref($domconfig{'login'}{$key}{$hostname}) eq 'HASH') {
+ if ($key eq 'loginvia') {
+ if ($domconfig{'login'}{'loginvia'}{$hostname}{'server'}) {
+ my $server = $domconfig{'login'}{'loginvia'}{$hostname}{'server'};
+ $designhash{$udom.'.login.loginvia'} = $server;
+ if ($domconfig{'login'}{'loginvia'}{$hostname}{'serverpath'} eq 'custom') {
+ $designhash{$udom.'.login.loginvia_'.$hostname} = $server.':'.$domconfig{'login'}{'loginvia'}{$hostname}{'custompath'};
+ } else {
+ $designhash{$udom.'.login.loginvia_'.$hostname} = $server.':'.$domconfig{'login'}{'loginvia'}{$hostname}{'serverpath'};
+ }
}
- if ($domconfig{'login'}{'loginvia'}{$hostname}{'exempt'}) {
- $designhash{$udom.'.login.loginvia_exempt_'.$hostname} = $domconfig{'login'}{'loginvia'}{$hostname}{'exempt'};
+ } elsif ($key eq 'headtag') {
+ if ($domconfig{'login'}{'headtag'}{$hostname}{'url'}) {
+ $designhash{$udom.'.login.headtag_'.$hostname} = $domconfig{'login'}{'headtag'}{$hostname}{'url'};
}
}
+ if ($domconfig{'login'}{$key}{$hostname}{'exempt'}) {
+ $designhash{$udom.'.login.'.$key.'_exempt_'.$hostname} = $domconfig{'login'}{$key}{$hostname}{'exempt'};
+ }
+ }
+ }
+ }
+ } elsif ($key eq 'saml') {
+ if (ref($domconfig{'login'}{$key}) eq 'HASH') {
+ foreach my $host (keys(%{$domconfig{'login'}{$key}})) {
+ if (ref($domconfig{'login'}{$key}{$host}) eq 'HASH') {
+ $designhash{$udom.'.login.'.$key.'_'.$host} = 1;
+ foreach my $item ('text','img','alt','url','title','notsso') {
+ $designhash{$udom.'.login.'.$key.'_'.$item.'_'.$host} = $domconfig{'login'}{$key}{$host}{$item};
+ }
}
}
}
@@ -4433,7 +5428,7 @@ sub get_legacy_domconf {
my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors';
my $designfile = $designdir.'/'.$udom.'.tab';
if (-e $designfile) {
- if ( open (my $fh,"<$designfile") ) {
+ if ( open (my $fh,'<',$designfile) ) {
while (my $line = <$fh>) {
next if ($line =~ /^\#/);
chomp($line);
@@ -4473,8 +5468,12 @@ sub domainlogo {
&Apache::lonnet::repcopy($local_name);
}
$imgsrc = &lonhttpdurl($imgsrc);
- }
- return '
';
+ }
+ my $alttext = $domain;
+ if ($designhash{$domain.'.login.alttext_domlogo'} ne '') {
+ $alttext = $designhash{$domain.'.login.alttext_domlogo'};
+ }
+ return '
';
} elsif (defined(&Apache::lonnet::domain($domain,'description'))) {
return &Apache::lonnet::domain($domain,'description');
} else {
@@ -4531,7 +5530,7 @@ sub designparm {
Inputs: $url (usually will be undef).
-Returns: Path to Construction Space containing the resource or
+Returns: Path to Authoring Space containing the resource or
directory being viewed (or for which action is being taken).
If $url is provided, and begins /priv/
/
the path will be that portion of the $context argument.
@@ -4594,7 +5593,7 @@ Input: (optional) filename from which br
is appropriate for use in building the breadcrumb trail.
Returns: HTML div with CSTR path and recent box
- To be included on Construction Space pages
+ To be included on Authoring Space pages
=cut
@@ -4609,7 +5608,7 @@ sub CSTR_pageheader {
my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'};
my ($udom,$uname,$thisdisfn)=
- ($trailfile =~ m{^\Q$londocroot\E/priv/([^/]+)/([^/]+)/(.*)$});
+ ($trailfile =~ m{^\Q$londocroot\E/priv/([^/]+)/([^/]+)(?:|/(.*))$});
my $formaction = "/priv/$udom/$uname/$thisdisfn";
$formaction =~ s{/+}{/}g;
@@ -4625,7 +5624,7 @@ sub CSTR_pageheader {
my $output =
''
.&Apache::loncommon::help_open_menu('','',3,'Authoring') #FIXME: Broken? Where is it?
- .'
'.&mt('Construction Space:').' '
+ .'
'.&mt('Authoring Space:').' '
.'
generation
+ no_inline_link -> if true and in remote mode, don't show the
+ 'Switch To Inline Menu' link
no_auto_mt_title -> prevent &mt()ing the title arg
- inherit_jsmath -> when creating popup window in a page,
- should it have jsmath forced on by the
- current page
bread_crumbs -> Array containing breadcrumbs
bread_crumbs_component -> if exists show it as headline else show only the breadcrumbs
+ bread_crumbs_nomenu -> if true will pass false as the value of $menulink
+ to lonhtmlcommon::breadcrumbs
+ group -> includes the current group, if page is for a
+ specific group
+ use_absolute -> for request for external resource or syllabus, this
+ will contain https:// if server uses
+ https (as per hosts.tab), but request is for http
+ hostname -> hostname, originally from $r->hostname(), (optional).
+ links_disabled -> Links in primary and secondary menus are disabled
+ (Can enable them once page has loaded - see lonroles.pm
+ for an example).
=back
@@ -6884,10 +8508,10 @@ sub start_page {
#&Apache::lonnet::logthis("start_page ".join(':',caller(0)));
$env{'internal.start_page'}++;
- my $result;
+ my ($result,@advtools);
if (! exists($args->{'skip_phases'}{'head'}) ) {
- $result .= &xml_begin() . &headtag($title, $head_extra, $args);
+ $result .= &xml_begin($args->{'frameset'}) . &headtag($title, $head_extra, $args);
}
if (! exists($args->{'skip_phases'}{'body'}) ) {
@@ -6901,7 +8525,8 @@ sub start_page {
$args->{'function'}, $args->{'add_entries'},
$args->{'only_body'}, $args->{'domain'},
$args->{'force_register'}, $args->{'no_nav_bar'},
- $args->{'bgcolor'}, $args);
+ $args->{'bgcolor'}, $args->{'no_inline_link'},
+ $args, \@advtools);
}
}
@@ -6930,13 +8555,28 @@ sub start_page {
&Apache::lonhtmlcommon::add_breadcrumb($crumb);
}
}
-
+ # if @advtools array contains items add then to the breadcrumbs
+ if (@advtools > 0) {
+ &Apache::lonmenu::advtools_crumbs(@advtools);
+ }
+ my $menulink;
+ # if arg: bread_crumbs_nomenu is true pass 0 as $menulink item.
+ if (exists($args->{'bread_crumbs_nomenu'})) {
+ $menulink = 0;
+ } else {
+ undef($menulink);
+ }
#if bread_crumbs_component exists show it as headline else show only the breadcrumbs
if(exists($args->{'bread_crumbs_component'})){
- $result .= &Apache::lonhtmlcommon::breadcrumbs($args->{'bread_crumbs_component'});
+ $result .= &Apache::lonhtmlcommon::breadcrumbs($args->{'bread_crumbs_component'},'',$menulink);
}else{
- $result .= &Apache::lonhtmlcommon::breadcrumbs();
+ $result .= &Apache::lonhtmlcommon::breadcrumbs('','',$menulink);
}
+ } elsif (($env{'environment.remote'} eq 'on') &&
+ ($env{'form.inhibitmenu'} ne 'yes') &&
+ ($env{'request.noversionuri'} =~ m{^/res/}) &&
+ ($env{'request.noversionuri'} !~ m{^/res/adm/pages/})) {
+ $result .= '
';
}
return $result;
}
@@ -6958,7 +8598,9 @@ sub end_page {
} else {
$result .= &endbodytag($args);
}
- $result .= "\n";
+ unless ($args->{'notbody'}) {
+ $result .= "\n";
+ }
if ($args->{'js_ready'}) {
$result = &js_ready($result);
@@ -6981,9 +8623,13 @@ function set_wishlistlink(title, path) {
title = document.title;
title = title.replace(/^LON-CAPA /,'');
}
+ title = encodeURIComponent(title);
+ title = title.replace("'","\\\'");
if (!path) {
path = location.pathname;
}
+ path = encodeURIComponent(path);
+ path = path.replace("'","\\\'");
Win = window.open('/adm/wishlist?mode=newLink&setTitle='+title+'&setPath='+path,
'wishlistNewLink','width=560,height=350,scrollbars=0');
}
@@ -7024,14 +8670,15 @@ var modalWindow = {
$(".LCmodal-overlay").click(function(){modalWindow.close();});
}
};
- var openMyModal = function(source,width,height,scrolling)
+ var openMyModal = function(source,width,height,scrolling,transparency,style)
{
+ source = source.replace(/'/g,"'");
modalWindow.windowId = "myModal";
modalWindow.width = width;
modalWindow.height = height;
- modalWindow.content = " ';
+ }
if ( exists( $env{'internal.head.redirect'} ) ) {
if (!(ref($args) eq 'HASH' && $args->{'noredirectlink'})) {
$endbodytag=
@@ -4902,6 +6016,9 @@ sub endbodytag {
$endbodytag;
}
}
+ if ((ref($args) eq 'HASH') && ($args->{'dashjs'})) {
+ $endbodytag = &Apache::lonhtmlcommon::dash_to_minus_js().$endbodytag;
+ }
return $endbodytag;
}
@@ -4940,7 +6057,7 @@ sub standard_css {
my $mono = 'monospace';
my $data_table_head = $sidebg;
my $data_table_light = '#FAFAFA';
- my $data_table_dark = '#F0F0F0';
+ my $data_table_dark = '#E0E0E0';
my $data_table_darker = '#CCCCCC';
my $data_table_highlight = '#FFFF00';
my $mail_new = '#FFBB77';
@@ -4980,7 +6097,6 @@ body {
a:focus,
a:focus img {
color: red;
- background: yellow;
}
form, .inline {
@@ -4995,6 +6111,14 @@ form, .inline {
vertical-align:middle;
}
+.LC_floatleft {
+ float: left;
+}
+
+.LC_floatright {
+ float: right;
+}
+
.LC_400Box {
width:400px;
}
@@ -5033,10 +6157,12 @@ form, .inline {
.LC_error {
color: red;
- font-size: larger;
}
-.LC_warning,
+.LC_warning {
+ color: darkorange;
+}
+
.LC_diff_removed {
color: red;
}
@@ -5059,6 +6185,17 @@ div.LC_confirm_box .LC_success img {
vertical-align: middle;
}
+.LC_maxwidth {
+ max-width: 100%;
+ height: auto;
+}
+
+.LC_textsize_mobile {
+ \@media only screen and (max-device-width: 480px) {
+ -webkit-text-size-adjust:100%; -moz-text-size-adjust:100%; -ms-text-size-adjust:100%;
+ }
+}
+
.LC_icon {
border: none;
vertical-align: middle;
@@ -5075,35 +6212,36 @@ div.LC_confirm_box .LC_success img {
}
.LC_discussion {
- background: $tabbg;
+ background: $data_table_dark;
border: 1px solid black;
margin: 2px;
}
-.LC_disc_action_links_bar {
- background: $tabbg;
- border: none;
- margin: 4px;
-}
-
.LC_disc_action_left {
+ background: $sidebg;
text-align: left;
+ padding: 4px;
+ margin: 2px;
}
.LC_disc_action_right {
+ background: $sidebg;
text-align: right;
+ padding: 4px;
+ margin: 2px;
}
.LC_disc_new_item {
background: white;
border: 2px solid red;
- margin: 2px;
+ margin: 4px;
+ padding: 4px;
}
.LC_disc_old_item {
background: white;
- border: 1px solid black;
- margin: 2px;
+ margin: 4px;
+ padding: 4px;
}
table.LC_pastsubmission {
@@ -5179,6 +6317,10 @@ table#LC_menubuttons img {
vertical-align: middle;
}
+.LC_breadcrumbs_hoverable {
+ background: $sidebg;
+}
+
td.LC_table_cell_checkbox {
text-align: center;
}
@@ -5198,11 +6340,11 @@ td.LC_table_cell_checkbox {
text-align: left;
}
-.LC_head_subbox {
+.LC_head_subbox, .LC_actionbox {
clear:both;
background: #F8F8F8; /* $sidebg; */
border: 1px solid $sidebg;
- margin: 0 0 10px 0;
+ margin: 0 0 10px 0;
padding: 3px;
text-align: left;
}
@@ -5225,7 +6367,7 @@ td.LC_table_cell_checkbox {
vertical-align: middle;
}
-li.LC_menubuttons_inline_text img,a {
+li.LC_menubuttons_inline_text img {
cursor:pointer;
text-decoration: none;
}
@@ -5249,6 +6391,11 @@ td.LC_menubuttons_text {
background: $tabbg;
}
+td.LC_zero_height {
+ line-height: 0;
+ cellpadding: 0;
+}
+
table.LC_data_table {
border: 1px solid #000000;
border-collapse: separate;
@@ -5335,7 +6482,8 @@ table.LC_nested tr.LC_empty_row td {
padding: 8px;
}
-table.LC_data_table tr.LC_empty_row td {
+table.LC_data_table tr.LC_empty_row td,
+table.LC_data_table tr.LC_footer_row td {
background-color: $sidebg;
}
@@ -5838,7 +6986,8 @@ table.LC_prior_tries td {
padding: 6px;
}
-.LC_answer_unknown {
+.LC_answer_unknown,
+.LC_answer_warning {
background: orange;
color: black;
padding: 6px;
@@ -5897,7 +7046,6 @@ div.LC_docs_entry_move {
table.LC_data_table tr > td.LC_docs_entry_commands,
table.LC_data_table tr > td.LC_docs_entry_parameter {
- background: #DDDDDD;
font-size: x-small;
}
@@ -5921,6 +7069,7 @@ table.LC_data_table tr > td.LC_docs_entr
color: #990000;
}
+.LC_domprefs_email,
.LC_docs_reinit_warn,
.LC_docs_ext_edit {
font-size: x-small;
@@ -6027,6 +7176,7 @@ div.LC_edit_problem_footer {
font-weight: normal;
font-size: medium;
margin: 2px;
+ background-color: $sidebg;
}
div.LC_edit_problem_header,
@@ -6035,7 +7185,7 @@ div.LC_edit_problem_footer,
div.LC_edit_problem_footer div,
div.LC_edit_problem_editxml_header,
div.LC_edit_problem_editxml_header div {
- margin-top: 5px;
+ z-index: 100;
}
div.LC_edit_problem_header_title {
@@ -6043,6 +7193,7 @@ div.LC_edit_problem_header_title {
font-size: larger;
background: $tabbg;
padding: 3px;
+ margin: 0 0 5px 0;
}
table.LC_edit_problem_header_title {
@@ -6050,14 +7201,34 @@ table.LC_edit_problem_header_title {
background: $tabbg;
}
-div.LC_edit_problem_discards {
- float: left;
- padding-bottom: 5px;
+div.LC_edit_actionbar {
+ background-color: $sidebg;
+ margin: 0;
+ padding: 0;
+ line-height: 200%;
}
-div.LC_edit_problem_saves {
- float: right;
- padding-bottom: 5px;
+div.LC_edit_actionbar div{
+ padding: 0;
+ margin: 0;
+ display: inline-block;
+}
+
+.LC_edit_opt {
+ padding-left: 1em;
+ white-space: nowrap;
+}
+
+.LC_edit_problem_latexhelper{
+ text-align: right;
+}
+
+#LC_edit_problem_colorful div{
+ margin-left: 40px;
+}
+
+#LC_edit_problem_codemirror div{
+ margin-left: 0px;
}
img.stift {
@@ -6074,13 +7245,13 @@ div.LC_createcourse {
}
.LC_dccid {
+ float: right;
margin: 0.2em 0 0 0;
padding: 0;
font-size: 90%;
display:none;
}
-a:hover,
ol.LC_primary_menu a:hover,
ol#LC_MenuBreadcrumbs a:hover,
ol#LC_PathBreadcrumbs a:hover,
@@ -6147,6 +7318,10 @@ fieldset {
/* overflow: hidden; */
}
+article.geogebraweb div {
+ margin: 0;
+}
+
fieldset > legend {
font-weight: bold;
padding: 0 5px 0 5px;
@@ -6172,9 +7347,8 @@ fieldset > legend {
}
ol.LC_primary_menu {
- float: right;
margin: 0;
- background-color: $pgbg_or_bgcolor;
+ padding: 0;
}
ol#LC_PathBreadcrumbs {
@@ -6182,14 +7356,91 @@ ol#LC_PathBreadcrumbs {
}
ol.LC_primary_menu li {
- display: inline;
- padding: 5px 5px 0 10px;
+ color: RGB(80, 80, 80);
+ vertical-align: middle;
+ text-align: left;
+ list-style: none;
+ position: relative;
+ float: left;
+ z-index: 100; /* will be displayed above codemirror and underneath the help-layer */
+ line-height: 1.5em;
+}
+
+ol.LC_primary_menu li a,
+ol.LC_primary_menu li p {
+ display: block;
+ margin: 0;
+ padding: 0 5px 0 10px;
+ text-decoration: none;
+}
+
+ol.LC_primary_menu li p span.LC_primary_menu_innertitle {
+ display: inline-block;
+ width: 95%;
+ text-align: left;
+}
+
+ol.LC_primary_menu li p span.LC_primary_menu_innerarrow {
+ display: inline-block;
+ width: 5%;
+ float: right;
+ text-align: right;
+ font-size: 70%;
+}
+
+ol.LC_primary_menu ul {
+ display: none;
+ width: 15em;
+ background-color: $data_table_light;
+ position: absolute;
+ top: 100%;
+}
+
+ol.LC_primary_menu ul ul {
+ left: 100%;
+ top: 0;
+}
+
+ol.LC_primary_menu li:hover > ul, ol.LC_primary_menu li.hover > ul {
+ display: block;
+ position: absolute;
+ margin: 0;
+ padding: 0;
+ z-index: 2;
+}
+
+ol.LC_primary_menu li:hover li, ol.LC_primary_menu li.hover li {
+/* First Submenu -> size should be smaller than the menu title of the whole menu */
+ font-size: 90%;
vertical-align: top;
+ float: none;
+ border-left: 1px solid black;
+ border-right: 1px solid black;
+/* A dark bottom border to visualize different menu options;
+overwritten in the create_submenu routine for the last border-bottom of the menu */
+ border-bottom: 1px solid $data_table_dark;
+}
+
+ol.LC_primary_menu li li p:hover {
+ color:$button_hover;
+ text-decoration:none;
+ background-color:$data_table_dark;
+}
+
+ol.LC_primary_menu li li a:hover {
+ color:$button_hover;
+ background-color:$data_table_dark;
+}
+
+/* Font-size equal to the size of the predecessors*/
+ol.LC_primary_menu li:hover li li {
+ font-size: 100%;
}
ol.LC_primary_menu li img {
vertical-align: bottom;
height: 1.1em;
+ margin: 0.2em 0 0 0;
}
ol.LC_primary_menu a {
@@ -6227,7 +7478,7 @@ ol.LC_docs_parameters li.LC_docs_paramet
}
ul#LC_secondary_menu {
- clear: both;
+ clear: right;
color: $fontmenu;
background: $tabbg;
list-style: none;
@@ -6235,15 +7486,52 @@ ul#LC_secondary_menu {
margin: 0;
width: 100%;
text-align: left;
+ float: left;
}
ul#LC_secondary_menu li {
font-weight: bold;
line-height: 1.8em;
+ border-right: 1px solid black;
+ float: left;
+}
+
+ul#LC_secondary_menu li.LC_hoverable:hover, ul#LC_secondary_menu li.hover {
+ background-color: $data_table_light;
+}
+
+ul#LC_secondary_menu li a {
padding: 0 0.8em;
+}
+
+ul#LC_secondary_menu li ul {
+ display: none;
+}
+
+ul#LC_secondary_menu li:hover ul, ul#LC_secondary_menu li.hover ul {
+ display: block;
+ position: absolute;
+ margin: 0;
+ padding: 0;
+ list-style:none;
+ float: none;
+ background-color: $data_table_light;
+ z-index: 2;
+ margin-left: -1px;
+}
+
+ul#LC_secondary_menu li ul li {
+ font-size: 90%;
+ vertical-align: top;
+ border-left: 1px solid black;
border-right: 1px solid black;
- display: inline;
- vertical-align: middle;
+ background-color: $data_table_light;
+ list-style:none;
+ float: none;
+}
+
+ul#LC_secondary_menu li ul li:hover, ul#LC_secondary_menu li ul li.hover {
+ background-color: $data_table_dark;
}
ul.LC_TabContent {
@@ -6314,6 +7602,12 @@ ul.LC_TabContent li.active a {
background:#FFFFFF;
outline: none;
}
+
+ul.LC_TabContent li.goback {
+ float: left;
+ border-left: none;
+}
+
#maincoursedoc {
clear:both;
}
@@ -6577,6 +7871,7 @@ ul#LC_toolbar {
list-style:none;
position:relative;
background-color:white;
+ overflow: auto;
}
ul#LC_toolbar li {
@@ -6586,6 +7881,7 @@ ul#LC_toolbar li {
float: left;
display:inline;
vertical-align:middle;
+ white-space: nowrap;
}
@@ -6682,6 +7978,80 @@ ul.LC_funclist li {
cursor:pointer;
}
+.LCisDisabled {
+ cursor: not-allowed;
+ opacity: 0.5;
+}
+
+a[aria-disabled="true"] {
+ color: currentColor;
+ display: inline-block; /* For IE11/ MS Edge bug */
+ pointer-events: none;
+ text-decoration: none;
+}
+
+pre.LC_wordwrap {
+ white-space: pre-wrap;
+ white-space: -moz-pre-wrap;
+ white-space: -pre-wrap;
+ white-space: -o-pre-wrap;
+ word-wrap: break-word;
+}
+
+/*
+ styles used by TTH when "Default set of options to pass to tth/m
+ when converting TeX" in course settings has been set
+
+ option passed: -t
+
+*/
+
+td div.comp { margin-top: -0.6ex; margin-bottom: -1ex;}
+td div.comb { margin-top: -0.6ex; margin-bottom: -.6ex;}
+td div.hrcomp { line-height: 0.9; margin-top: -0.8ex; margin-bottom: -1ex;}
+td div.norm {line-height:normal;}
+
+/*
+ option passed -y3
+*/
+
+span.roman {font-family: serif; font-style: normal; font-weight: normal;}
+span.overacc2 {position: relative; left: .8em; top: -1.2ex;}
+span.overacc1 {position: relative; left: .6em; top: -1.2ex;}
+
+#LC_minitab_header {
+ float:left;
+ width:100%;
+ background:#DAE0D2 url("/res/adm/pages/minitabmenu_bg.gif") repeat-x bottom;
+ font-size:93%;
+ line-height:normal;
+ margin: 0.5em 0 0.5em 0;
+}
+#LC_minitab_header ul {
+ margin:0;
+ padding:10px 10px 0;
+ list-style:none;
+}
+#LC_minitab_header li {
+ float:left;
+ background:url("/res/adm/pages/minitabmenu_left.gif") no-repeat left top;
+ margin:0;
+ padding:0 0 0 9px;
+}
+#LC_minitab_header a {
+ display:block;
+ background:url("/res/adm/pages/minitabmenu_right.gif") no-repeat right top;
+ padding:5px 15px 4px 6px;
+}
+#LC_minitab_header #LC_current_minitab {
+ background-image:url("/res/adm/pages/minitabmenu_left_on.gif");
+}
+#LC_minitab_header #LC_current_minitab a {
+ background-image:url("/res/adm/pages/minitabmenu_right_on.gif");
+ padding-bottom:5px;
+}
+
+
END
}
@@ -6703,6 +8073,7 @@ Inputs: $title - optional title for the
(side effect of setting
$env{'internal.head.redirect'} to the url
redirected too)
+ 4- whether encrypt check should be skipped
domain -> force to color decorate a page for a specific
domain
function -> force usage of a specific rolish color scheme
@@ -6718,6 +8089,7 @@ sub headtag {
my $function = $args->{'function'} || &get_users_function();
my $domain = $args->{'domain'} || &determinedomain();
my $bgcolor = $args->{'bgcolor'} || &designparm($function.'.pgbg',$domain);
+ my $httphost = $args->{'use_absolute'};
my $url = join(':',$env{'user.name'},$env{'user.domain'},
$Apache::lonnet::perlvar{'lonVersion'},
#time(),
@@ -6728,18 +8100,23 @@ sub headtag {
my $result =
'
'.
- &font_settings();
+ &font_settings($args);
+
+ my $inhibitprint;
+ if ($args->{'print_suppress'}) {
+ $inhibitprint = &print_suppression();
+ }
if (!$args->{'frameset'}) {
$result .= &Apache::lonhtmlcommon::htmlareaheaders();
}
- if ($args->{'force_register'} && $env{'request.noversionuri'} !~ m{^/res/adm/pages/}) {
- $result .= Apache::lonxml::display_title();
+ if ($args->{'force_register'}) {
+ $result .= &Apache::lonmenu::registerurl(1);
}
if (!$args->{'no_nav_bar'}
&& !$args->{'only_body'}
&& !$args->{'frameset'}) {
- $result .= &help_menu_js();
+ $result .= &help_menu_js($httphost);
$result.=&modal_window();
$result.=&togglebox_script();
$result.=&wishlist_window();
@@ -6759,8 +8136,10 @@ sub headtag {
}
}
if (ref($args->{'redirect'})) {
- my ($time,$url,$inhibit_continue) = @{$args->{'redirect'}};
- $url = &Apache::lonenc::check_encrypt($url);
+ my ($time,$url,$inhibit_continue,$skip_enc_check) = @{$args->{'redirect'}};
+ if (!$skip_enc_check) {
+ $url = &Apache::lonenc::check_encrypt($url);
+ }
if (!$inhibit_continue) {
$env{'internal.head.redirect'} = $url;
}
@@ -6768,14 +8147,162 @@ sub headtag {
ADDMETA
+ } else {
+ unless (($args->{'frameset'}) || ($args->{'js_ready'}) || ($args->{'only_body'}) || ($args->{'no_nav_bar'})) {
+ my $requrl = $env{'request.uri'};
+ if ($requrl eq '') {
+ $requrl = $ENV{'REQUEST_URI'};
+ $requrl =~ s/\?.+$//;
+ }
+ unless (($requrl =~ m{^/adm/(?:switchserver|login|authenticate|logout|groupsort|cleanup|helper|slotrequest|grades)(\?|$)}) ||
+ (($requrl =~ m{^/res/}) && (($env{'form.submitted'} eq 'scantron') ||
+ ($env{'form.grade_symb'}) || ($Apache::lonhomework::scantronmode)))) {
+ my $dom_in_use = $Apache::lonnet::perlvar{'lonDefDomain'};
+ unless (&Apache::lonnet::allowed('mau',$dom_in_use)) {
+ my %domdefs = &Apache::lonnet::get_domain_defaults($dom_in_use);
+ my $lonhost = $Apache::lonnet::perlvar{'lonHostID'};
+ my ($offload,$offloadoth);
+ if (ref($domdefs{'offloadnow'}) eq 'HASH') {
+ if ($domdefs{'offloadnow'}{$lonhost}) {
+ $offload = 1;
+ if (($env{'user.domain'} ne '') && ($env{'user.domain'} ne $dom_in_use) &&
+ (!(($env{'user.name'} eq 'public') && ($env{'user.domain'} eq 'public')))) {
+ unless (&Apache::lonnet::shared_institution($env{'user.domain'})) {
+ $offloadoth = 1;
+ $dom_in_use = $env{'user.domain'};
+ }
+ }
+ }
+ }
+ unless ($offload) {
+ if (ref($domdefs{'offloadoth'}) eq 'HASH') {
+ if ($domdefs{'offloadoth'}{$lonhost}) {
+ if (($env{'user.domain'} ne '') && ($env{'user.domain'} ne $dom_in_use) &&
+ (!(($env{'user.name'} eq 'public') && ($env{'user.domain'} eq 'public')))) {
+ unless (&Apache::lonnet::shared_institution($env{'user.domain'})) {
+ $offload = 1;
+ $offloadoth = 1;
+ $dom_in_use = $env{'user.domain'};
+ }
+ }
+ }
+ }
+ }
+ if ($offload) {
+ my $newserver = &Apache::lonnet::spareserver(undef,30000,undef,1,$dom_in_use);
+ if (($newserver eq '') && ($offloadoth)) {
+ my @domains = &Apache::lonnet::current_machine_domains();
+ if (($dom_in_use ne '') && (!grep(/^\Q$dom_in_use\E$/,@domains))) {
+ ($newserver) = &Apache::lonnet::choose_server($dom_in_use);
+ }
+ }
+ if (($newserver) && ($newserver ne $lonhost)) {
+ my $numsec = 5;
+ my $timeout = $numsec * 1000;
+ my ($newurl,$locknum,%locks,$msg);
+ if ($env{'request.role.adv'}) {
+ ($locknum,%locks) = &Apache::lonnet::get_locks();
+ }
+ my $disable_submit = 0;
+ if ($requrl =~ /$LONCAPA::assess_re/) {
+ $disable_submit = 1;
+ }
+ if ($locknum) {
+ my @lockinfo = sort(values(%locks));
+ $msg = &mt('Once the following tasks are complete:')." \n".
+ join(", ",sort(values(%locks)))."\n";
+ if (&show_course()) {
+ $msg .= &mt('your session will be transferred to a different server, after you click "Courses".');
+ } else {
+ $msg .= &mt('your session will be transferred to a different server, after you click "Roles".');
+ }
+ } else {
+ if (($requrl =~ m{^/res/}) && ($env{'form.submitted'} =~ /^part_/)) {
+ $msg = &mt('Your LON-CAPA submission has been recorded')."\n";
+ }
+ $msg .= &mt('Your current LON-CAPA session will be transferred to a different server in [quant,_1,second].',$numsec);
+ $newurl = '/adm/switchserver?otherserver='.$newserver;
+ if (($env{'request.role'}) && ($env{'request.role'} ne 'cm')) {
+ $newurl .= '&role='.$env{'request.role'};
+ }
+ if ($env{'request.symb'}) {
+ my $shownsymb = &Apache::lonenc::check_encrypt($env{'request.symb'});
+ if ($shownsymb =~ m{^/enc/}) {
+ my $reqdmajor = 2;
+ my $reqdminor = 11;
+ my $reqdsubminor = 3;
+ my $newserverrev = &Apache::lonnet::get_server_loncaparev('',$newserver);
+ my $remoterev = &Apache::lonnet::get_server_loncaparev(undef,$newserver);
+ my ($major,$minor,$subminor) = ($remoterev =~ /^\'?(\d+)\.(\d+)\.(\d+|)[\w.\-]+\'?$/);
+ if (($major eq '' && $minor eq '') ||
+ (($reqdmajor > $major) || (($reqdmajor == $major) && ($reqdminor > $minor)) ||
+ (($reqdmajor == $major) && ($reqdminor == $minor) && (($subminor eq '') ||
+ ($reqdsubminor > $subminor))))) {
+ undef($shownsymb);
+ }
+ }
+ if ($shownsymb) {
+ &js_escape(\$shownsymb);
+ $newurl .= '&symb='.$shownsymb;
+ }
+ } else {
+ my $shownurl = &Apache::lonenc::check_encrypt($requrl);
+ &js_escape(\$shownurl);
+ $newurl .= '&origurl='.$shownurl;
+ }
+ }
+ &js_escape(\$msg);
+ $result.=<
+
+OFFLOAD
+ }
+ }
+ }
+ }
+ }
}
if (!defined($title)) {
$title = 'The LearningOnline Network with CAPA';
}
if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); }
$result .= '