--- loncom/interface/loncommon.pm 2014/04/23 10:11:26 1.1185 +++ loncom/interface/loncommon.pm 2015/04/03 17:31:24 1.1211 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # a pile of common routines # -# $Id: loncommon.pm,v 1.1185 2014/04/23 10:11:26 raeburn Exp $ +# $Id: loncommon.pm,v 1.1211 2015/04/03 17:31:24 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -1316,8 +1316,10 @@ sub helpLatexCheatsheet { .&help_open_topic('Other_Symbols',&mt('Other Symbols'),$stayOnPage,undef,600) .''; unless ($not_author) { - $out .= ' ' - .&help_open_topic('Authoring_Output_Tags',&mt('Output Tags'),$stayOnPage,undef,600) + $out .= '' + .&help_open_topic('Authoring_Output_Tags',&mt('Output Tags'),$stayOnPage,undef,600) + .' ' + .&help_open_topic('Authoring_Multilingual_Problems',&mt('How to create problems in different languages'),$stayOnPage,undef,600) .''; } $out .= ''; # End cheatsheet @@ -1755,6 +1757,241 @@ 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 @@ -2363,6 +2600,8 @@ Outputs: =item * $clientinfo +=item * $clientosversion + =back =back @@ -2382,8 +2621,9 @@ sub decode_user_agent { 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; @@ -2403,7 +2643,12 @@ 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); @@ -2414,7 +2659,8 @@ sub decode_user_agent { $clientinfo = 'chromeframe-'.$1; } return ($httpbrowser,$clientbrowser,$clientversion,$clientmathml, - $clientunicode,$clientos,$clientmobile,$clientinfo); + $clientunicode,$clientos,$clientmobile,$clientinfo, + $clientosversion); } ############################################################### @@ -3750,7 +3996,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: @@ -3772,6 +4018,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. @@ -3779,7 +4030,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) { @@ -3795,7 +4046,7 @@ sub get_previous_attempt { } $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); @@ -3812,6 +4063,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) { @@ -3823,17 +4086,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 .= ''; + } + $prevattempts .= ''; if (@hidden) { foreach my $key (sort(keys(%lasthash))) { next if ($key =~ /\.foilorder$/); @@ -4320,23 +4626,20 @@ sub findallcourses { ############################################### sub blockcheck { - my ($setters,$activity,$uname,$udom,$url) = @_; + my ($setters,$activity,$uname,$udom,$url,$is_course) = @_; - if (!defined($udom)) { + 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); + return ($startblock,$endblock,$triggerblock); + } + } else { $udom = $env{'user.domain'}; - } - if (!defined($uname)) { $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 ($startblock,$endblock,$triggerblock) = - &get_blocks($setters,$activity,$udom,$uname,$url); - return ($startblock,$endblock,$triggerblock); - } - my $startblock = 0; my $endblock = 0; my $triggerblock = ''; @@ -4346,7 +4649,8 @@ sub blockcheck { # 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}); @@ -4610,12 +4914,12 @@ sub parse_block_record { } sub blocking_status { - my ($activity,$uname,$udom,$url) = @_; + my ($activity,$uname,$udom,$url,$is_course) = @_; my %setters; # check for active blocking my ($startblock,$endblock,$triggerblock) = - &blockcheck(\%setters,$activity,$uname,$udom,$url); + &blockcheck(\%setters,$activity,$uname,$udom,$url,$is_course); my $blocked = 0; if ($startblock && $endblock) { $blocked = 1; @@ -4670,13 +4974,13 @@ END_BLOCK ############################################### 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=$env{'request.host'} || $ENV{'REMOTE_ADDR'} || $clientip; my $name; foreach my $pattern (split(',',$acc)) { @@ -4772,23 +5076,29 @@ 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'}; + } } } } @@ -6486,6 +6796,7 @@ 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 { @@ -6503,7 +6814,12 @@ table.LC_edit_problem_header_title { div.LC_edit_problem_discards { float: left; - padding-bottom: 5px; +} + +div.LC_edit_actionbar { + margin: -5px 0px 0px 0px !important; + background-color: $sidebg; + height: 31px; } div.LC_edit_problem_saves { @@ -6524,6 +6840,10 @@ div.LC_edit_problem_saves { margin-left: 40px; } +#LC_edit_problem_codemirror div{ + margin-left: 0px; +} + img.stift { border-width: 0; vertical-align: middle; @@ -6611,6 +6931,10 @@ fieldset { /* overflow: hidden; */ } +article.geogebraweb div { + margin: 0; +} + fieldset > legend { font-weight: bold; padding: 0 5px 0 5px; @@ -6638,7 +6962,6 @@ fieldset > legend { ol.LC_primary_menu { margin: 0; padding: 0; - background-color: $pgbg_or_bgcolor; } ol#LC_PathBreadcrumbs { @@ -6650,23 +6973,48 @@ ol.LC_primary_menu li { 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 a, +ol.LC_primary_menu li p { display: block; margin: 0; padding: 0 5px 0 10px; text-decoration: none; } -ol.LC_primary_menu li ul { +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: 10em; + 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 { +ol.LC_primary_menu li:hover > ul, ol.LC_primary_menu li.hover > ul { display: block; position: absolute; margin: 0; @@ -6675,15 +7023,21 @@ ol.LC_primary_menu li:hover ul, ol.LC_pr } 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:hover li a, ol.LC_primary_menu li.hover li a { - background-color:$data_table_light; +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 { @@ -6691,6 +7045,11 @@ ol.LC_primary_menu li li a: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; @@ -7302,7 +7661,10 @@ sub headtag { ''. &font_settings($args); - my $inhibitprint = &print_suppression(); + my $inhibitprint; + if ($args->{'print_suppress'}) { + $inhibitprint = &print_suppression(); + } if (!$args->{'frameset'}) { $result .= &Apache::lonhtmlcommon::htmlareaheaders(); @@ -7342,6 +7704,79 @@ 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); + if (ref($domdefs{'offloadnow'}) eq 'HASH') { + my $lonhost = $Apache::lonnet::perlvar{'lonHostID'}; + if ($domdefs{'offloadnow'}{$lonhost}) { + my $newserver = &Apache::lonnet::spareserver(30000,undef,1,$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". + &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'}) { + $newurl .= '&symb='.$env{'request.symb'}; + } else { + $newurl .= '&origurl='.$requrl; + } + } + $result.=< + +OFFLOAD + } + } + } + } + } + } } if (!defined($title)) { $title = 'The LearningOnline Network with CAPA'; @@ -7428,7 +7863,7 @@ sub print_suppression { } my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; - my $blocked = &blocking_status('printout',$cnum,$cdom); + my $blocked = &blocking_status('printout',$cnum,$cdom,undef,1); if ($blocked) { my $checkrole = "cm./$cdom/$cnum"; if ($env{'request.course.sec'} ne '') { @@ -7661,10 +8096,12 @@ function set_wishlistlink(title, path) { 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'); } @@ -7707,12 +8144,13 @@ var modalWindow = { }; var openMyModal = function(source,width,height,scrolling,transparency,style) { + source = source.replace("'","'"); modalWindow.windowId = "myModal"; modalWindow.width = width; modalWindow.height = height; - modalWindow.content = ""; modalWindow.open(); - }; + }; // END LON-CAPA Internal --> // ]]> @@ -8314,7 +8752,7 @@ role status: active, previous or future. sub check_user_status { my ($udom,$uname,$cdom,$crs,$role,$sec) = @_; my %userinfo = &Apache::lonnet::dump('roles',$udom,$uname); - my @uroles = keys %userinfo; + my @uroles = keys(%userinfo); my $srchstr; my $active_chk = 'none'; my $now = time; @@ -9897,7 +10335,15 @@ sub ask_for_embedded_content { ($path) = ($toplevel =~ m{^(\Q/uploaded/$cdom/$cnum/\E(?:docs|supplemental)/(?:default|\d+)/\d+)/}); } - $fileloc = &Apache::lonnet::filelocation('',$toplevel); + if ($toplevel=~/^\/*(uploaded|editupload)/) { + $fileloc = $toplevel; + $fileloc=~ s/^\s*(\S+)\s*$/$1/; + my ($udom,$uname,$fname) = + ($fileloc=~ m{^/+(?:uploaded|editupload)/+($match_domain)/+($match_name)/+(.*)$}); + $fileloc = propath($udom,$uname).'/userfiles/'.$fname; + } else { + $fileloc = &Apache::lonnet::filelocation('',$toplevel); + } $fileloc =~ s{^/}{}; ($filename) = ($fileloc =~ m{.+/([^/]+)$}); $heading = &mt('Status of dependencies in [_1]',"$title ($filename)"); @@ -11053,7 +11499,7 @@ sub decompress_form { "$topdir/media/player.swf", "$topdir/media/swfobject.js", "$topdir/media/expressInstall.swf"); - my @camtasia8 = ("$topdir/","$topdir/$topdir.html", + my @camtasia8_1 = ("$topdir/","$topdir/$topdir.html", "$topdir/$topdir.mp4", "$topdir/$topdir\_config.xml", "$topdir/$topdir\_controller.swf", @@ -11075,13 +11521,36 @@ sub decompress_form { "$topdir/skins/express_show/", "$topdir/skins/express_show/player-min.css", "$topdir/skins/express_show/spritesheet.png"); + my @camtasia8_4 = ("$topdir/","$topdir/$topdir.html", + "$topdir/$topdir.mp4", + "$topdir/$topdir\_config.xml", + "$topdir/$topdir\_controller.swf", + "$topdir/$topdir\_embed.css", + "$topdir/$topdir\_First_Frame.png", + "$topdir/$topdir\_player.html", + "$topdir/$topdir\_Thumbnails.png", + "$topdir/playerProductInstall.swf", + "$topdir/scripts/", + "$topdir/scripts/config_xml.js", + "$topdir/scripts/techsmith-smart-player.min.js", + "$topdir/skins/", + "$topdir/skins/configuration_express.xml", + "$topdir/skins/express_show/", + "$topdir/skins/express_show/spritesheet.min.css", + "$topdir/skins/express_show/spritesheet.png", + "$topdir/skins/express_show/techsmith-smart-player.min.css"); my @diffs = &compare_arrays(\@paths,\@camtasia6); if (@diffs == 0) { $is_camtasia = 6; } else { - @diffs = &compare_arrays(\@paths,\@camtasia8); + @diffs = &compare_arrays(\@paths,\@camtasia8_1); if (@diffs == 0) { $is_camtasia = 8; + } else { + @diffs = &compare_arrays(\@paths,\@camtasia8_4); + if (@diffs == 0) { + $is_camtasia = 8; + } } } } @@ -11095,7 +11564,6 @@ function camtasiaToggle() { for (var i=0; i{'robot'} ? 'robot'.$args->{'robot'} @@ -14520,8 +14999,8 @@ sub init_user_environment { } # ------------------------------------ Check browser type and MathML capability - my ($httpbrowser,$clientbrowser,$clientversion,$clientmathml, - $clientunicode,$clientos,$clientmobile,$clientinfo) = &decode_user_agent($r); + my ($httpbrowser,$clientbrowser,$clientversion,$clientmathml,$clientunicode, + $clientos,$clientmobile,$clientinfo,$clientosversion) = &decode_user_agent($r); # ------------------------------------------------------------- Get environment @@ -14554,6 +15033,7 @@ sub init_user_environment { "browser.os" => $clientos, "browser.mobile" => $clientmobile, "browser.info" => $clientinfo, + "browser.osversion" => $clientosversion, "server.domain" => $Apache::lonnet::perlvar{'lonDefDomain'}, "request.course.fn" => '', "request.course.uri" => '', @@ -14880,7 +15360,7 @@ sub build_filters { } $cloneableonlyform = ''.(' 'x3).''; if ($formname eq 'ccrs') { - $cloneabletitle = &mt('Cloneable for').' '.$cloneruname.':'.$clonerudom; + $cloneabletitle = &mt('Cloneable for [_1]',$cloneruname.':'.$clonerudom); } else { $cloneabletitle = &mt('Cloneable by you'); } @@ -14924,7 +15404,12 @@ sub build_filters { $output .= ''."\n". ''."\n"; - } elsif ($formname ne 'quotacheck') { + } elsif ($formname eq 'quotacheck') { + $output .= qq| + + +|; + } else { my $name_input; if ($cnameelement ne '') { $name_input = ''.&mt("No suitable server could be found amongst servers in your own domain (which is also the course's domain)."); + } + } else { + $otherserver = $userdomserver; } - } else { - push(@{$checkparms->{$name}},$value); } - } elsif ($item eq 'resourcetag') { - if ($name eq 'responsetype') { - $checkresponsetypes->{$value} = $Apache::lonnet::needsrelease{$key} + if ($otherserver ne '') { + $switchserver = 'otherserver='.$otherserver.'&role='.$rolecode; } - } elsif ($item eq 'course') { - if ($name eq 'crstype') { - $checkcrstypes->{$value} = $Apache::lonnet::needsrelease{$key}; + } + } + return ($switchserver,$warning); +} + +=pod + +=item * &check_release_result() + +Inputs: + +$switchwarning - Warning message if no suitable server found to host session. + +$switchserver - query string to append to /adm/switchserver containing lonHostID + and current role. + +Returns: HTML to display with information about requirement to switch server. + Either displaying warning with link to Roles/Courses screen or + display link to switchserver. + +=cut + +sub check_release_result { + my ($switchwarning,$switchserver) = @_; + my $output = &start_page('Selected course unavailable on this server'). + '

'; + if ($switchwarning) { + $output .= $switchwarning.'
'; + if (&show_course()) { + $output .= &mt('Display courses'); + } else { + $output .= &mt('Display roles'); + } + $output .= ''; + } elsif ($switchserver) { + $output .= &mt('This course requires a newer version of LON-CAPA than is installed on this server.'). + '
'. + ''. + &mt('Switch Server'). + ''; + } + $output .= '

'.&end_page(); + return $output; +} + +=pod + +=item * &needs_coursereinit() + +Determine if course contents stored for user's session needs to be +refreshed, because content has changed since "Big Hash" last tied. + +Check for change is made if time last checked is more than 10 minutes ago +(by default). + +Inputs: + +$loncaparev - Version on current server (format: Major.Minor.Subrelease-datestamp) + +$interval (optional) - Time which may elapse (in s) between last check for content + change in current course. (default: 600 s). + +Returns: an array; first element is: + +=over 4 + +'switch' - if content updates mean user's session + needs to be switched to a server running a newer LON-CAPA version + +'update' - if course session needs to be refreshed (i.e., Big Hash needs to be reloaded) + on current server hosting user's session + +'' - if no action required. + +=back + +If first item element is 'switch': + +second item is $switchwarning - Warning message if no suitable server found to host session. + +third item is $switchserver - query string to append to /adm/switchserver containing lonHostID + and current role. + +otherwise: no other elements returned. + +=back + +=cut + +sub needs_coursereinit { + my ($loncaparev,$interval) = @_; + return() unless ($env{'request.course.id'} && $env{'request.course.tied'}); + my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + my $now = time; + if ($interval eq '') { + $interval = 600; + } + if (($now-$env{'request.course.timechecked'})>$interval) { + my $lastchange = &Apache::lonnet::get_coursechange($cdom,$cnum); + &Apache::lonnet::appenv({'request.course.timechecked'=>$now}); + if ($lastchange > $env{'request.course.tied'}) { + my %curr_reqd_hash = &Apache::lonnet::userenvironment($cdom,$cnum,'internal.releaserequired'); + if ($curr_reqd_hash{'internal.releaserequired'} ne '') { + my $required = $env{'course.'.$cdom.'_'.$cnum.'.internal.releaserequired'}; + if ($curr_reqd_hash{'internal.releaserequired'} ne $required) { + &Apache::lonnet::appenv({'course.'.$cdom.'_'.$cnum.'.internal.releaserequired' => + $curr_reqd_hash{'internal.releaserequired'}}); + my ($switchserver,$switchwarning) = + &check_release_required($loncaparev,$cdom.'_'.$cnum,$env{'request.role'}, + $curr_reqd_hash{'internal.releaserequired'}); + if ($switchwarning ne '' || $switchserver ne '') { + return ('switch',$switchwarning,$switchserver); + } + } } + return ('update'); } } - ($anonsurvey->{major},$anonsurvey->{minor}) = split(/\./,$Apache::lonnet::needsrelease{'parameter:type:anonsurvey'}); - ($randomizetry->{major},$randomizetry->{minor}) = split(/\./,$Apache::lonnet::needsrelease{'parameter:type:randomizetry'}); - return; + return (); } sub update_content_constraints { @@ -15631,6 +16283,26 @@ sub cleanup_html { return $outgoing; } +# Checks for critical messages and returns a redirect url if one exists. +# $interval indicates how often to check for messages. +sub critical_redirect { + my ($interval) = @_; + if ((time-$env{'user.criticalcheck.time'})>$interval) { + my @what=&Apache::lonnet::dump('critical', $env{'user.domain'}, + $env{'user.name'}); + &Apache::lonnet::appenv({'user.criticalcheck.time'=>time}); + my $redirecturl; + if ($what[0]) { + if (($what[0] ne 'con_lost') && ($what[0]!~/^error\:/)) { + $redirecturl='/adm/email?critical=display'; + my $url=&Apache::lonnet::absolute_url().$redirecturl; + return (1, $url); + } + } + } + return (); +} + # Use: # my $answer=reply("encrypt:passwd:$udom:$uname:$upass",$tryserver); #