--- loncom/interface/loncommon.pm 2021/09/05 05:55:50 1.1365
+++ loncom/interface/loncommon.pm 2024/09/11 00:40:07 1.1436
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# a pile of common routines
#
-# $Id: loncommon.pm,v 1.1365 2021/09/05 05:55:50 raeburn Exp $
+# $Id: loncommon.pm,v 1.1436 2024/09/11 00:40:07 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -61,7 +61,7 @@ use POSIX qw(strftime mktime);
use Apache::lonmenu();
use Apache::lonenc();
use Apache::lonlocal;
-use Apache::lonnet();
+use Apache::lonnavmaps();
use HTML::Entities;
use Apache::lonhtmlcommon();
use Apache::loncoursedata();
@@ -71,7 +71,9 @@ use Apache::lonuserutils();
use Apache::lonuserstate();
use Apache::courseclassifier();
use LONCAPA qw(:DEFAULT :match);
+use LONCAPA::ltiutils;
use LONCAPA::LWPReq;
+use LONCAPA::map();
use HTTP::Request;
use DateTime::TimeZone;
use DateTime::Locale;
@@ -435,7 +437,7 @@ sub studentbrowser_javascript {
+
+ENDJS
+
+}
+
+=pod
+
+=item * &iframe_wrapper_resizejs()
+
+emits javascript used to handle resizing for a page containing
+an iframe, to ensure that the iframe does not obscure any
+standard LON-CAPA menu items.
+
+=back
+
+=cut
+
+#
+# jQuery to use when iframe is in use and a page resize occurs.
+# This script will ensure that the iframe does not obscure any
+# standard LON-CAPA inline menus (primary, secondary, and/or
+# breadcrumbs and Functions menus. Expects javascript from
+# &iframe_wrapper_headjs() to be in head portion of the web page,
+# e.g., by inclusion in second arg passed to &start_page().
+#
+
+sub iframe_wrapper_resizejs {
+ my $offset = 5;
+ &get_unprocessed_cgi($ENV{'QUERY_STRING'},['inhibitmenu']);
+ if (($env{'form.inhibitmenu'} eq 'yes') || ($env{'form.only_body'})) {
+ $offset = 0;
+ }
+ return &Apache::lonhtmlcommon::scripttag(<
+ENDJS
+ }
$endbodytag=
- "
".
+ "$endbodyjs
".
&mt('Continue').''.
$endbodytag;
}
}
+ if ((ref($args) eq 'HASH') && ($args->{'dashjs'})) {
+ $endbodytag = &Apache::lonhtmlcommon::dash_to_minus_js().$endbodytag;
+ }
return $endbodytag;
}
@@ -6461,6 +7274,7 @@ body {
line-height:130%;
font-size:0.83em;
color:$font;
+ background-color: $pgbg_or_bgcolor;
}
a:focus,
@@ -6472,6 +7286,14 @@ form, .inline {
display: inline;
}
+.LC_menus_content.shown{
+ display: block;
+}
+
+.LC_menus_content.hidden {
+ display: none;
+}
+
.LC_right {
text-align:right;
}
@@ -6492,6 +7314,12 @@ form, .inline {
width:400px;
}
+#LC_collapsible_separator {
+ border: 1px solid black;
+ width: 99.9%;
+ height: 0px;
+}
+
.LC_iframecontainer {
width: 98%;
margin: 0;
@@ -7704,6 +8532,11 @@ fieldset {
/* overflow: hidden; */
}
+fieldset#LC_selectuser {
+ margin: 0;
+ padding: 0;
+}
+
article.geogebraweb div {
margin: 0;
}
@@ -8247,6 +9080,10 @@ a#LC_content_toolbar_edittoplevel {
background-image:url(/res/adm/pages/edittoplevel.gif);
}
+a#LC_content_toolbar_printout {
+ background-image:url(/res/adm/pages/printout.gif);
+}
+
ul#LC_toolbar li a:hover {
background-position: bottom center;
}
@@ -8364,6 +9201,18 @@ 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;
@@ -8537,7 +9386,13 @@ Inputs: $title - optional title for the
3- whether the side effect should occur
(side effect of setting
$env{'internal.head.redirect'} to the url
- redirected too)
+ redirected to)
+ 4- whether the redirect target should be
+ the opener of the current (pop-up)
+ window (side effect of setting
+ $env{'internal.head.to_opener'} to
+ 1, if true.
+ 5- 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
@@ -8600,15 +9455,45 @@ sub headtag {
}
}
if (ref($args->{'redirect'})) {
- my ($time,$url,$inhibit_continue) = @{$args->{'redirect'}};
- $url = &Apache::lonenc::check_encrypt($url);
+ my ($time,$url,$inhibit_continue,$to_opener,$skip_enc_check) = @{$args->{'redirect'}};
+ if (!$skip_enc_check) {
+ $url = &Apache::lonenc::check_encrypt($url);
+ }
if (!$inhibit_continue) {
$env{'internal.head.redirect'} = $url;
}
- $result.=<
+ADDMETA
+ if ($to_opener) {
+ $env{'internal.head.to_opener'} = 1;
+ my $dest = &js_escape($url);
+ my $timeout = int($time * 1000);
+ $result .=<<"ENDJS";
+
+ENDJS
+ } else {
+ $result.=<<"ADDMETA";
ADDMETA
+ }
} else {
unless (($args->{'frameset'}) || ($args->{'js_ready'}) || ($args->{'only_body'}) || ($args->{'no_nav_bar'})) {
my $requrl = $env{'request.uri'};
@@ -8745,8 +9630,12 @@ OFFLOAD
$title = 'The LearningOnline Network with CAPA';
}
if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); }
- $result .= '
LON-CAPA '.$title.''
- .'';
+ } else {
+ $result .= ' LON-CAPA '.$title.'';
+ }
+ $result .= "\n".'{'frameset'}) {
$result .= ' /';
}
@@ -8761,7 +9650,7 @@ OFFLOAD
}
if ($clientmobile) {
$result .= '
-
+
';
}
$result .= ''."\n";
@@ -8833,7 +9722,8 @@ 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,undef,1);
+ my $clientip = &Apache::lonnet::get_requestor_ip();
+ my $blocked = &blocking_status('printout',$clientip,$cnum,$cdom,undef,1);
if ($blocked) {
my $checkrole = "cm./$cdom/$cnum";
if ($env{'request.course.sec'} ne '') {
@@ -8952,6 +9842,10 @@ $args - additional optional args support
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).
+ links_target -> Target for links, e.g., _parent (optional).
=back
@@ -9040,6 +9934,7 @@ sub start_page {
}
}
+ my $showncrumbs;
if (! exists($args->{'skip_phases'}{'body'}) ) {
if ($args->{'frameset'}) {
my $attr_string = &make_attr_string($args->{'force_register'},
@@ -9052,7 +9947,8 @@ sub start_page {
$args->{'only_body'}, $args->{'domain'},
$args->{'force_register'}, $args->{'no_nav_bar'},
$args->{'bgcolor'}, $args,
- \@advtools,$ltiscope,$ltiuri,\%ltimenu,$menucoll,\%menu);
+ \@advtools,$ltiscope,$ltiuri,\%ltimenu,$menucoll,
+ \%menu,\$showncrumbs);
}
}
@@ -9074,6 +9970,7 @@ sub start_page {
#Breadcrumbs
if (exists($args->{'bread_crumbs'}) or exists($args->{'bread_crumbs_component'})) {
+ unless ($showncrumbs) {
&Apache::lonhtmlcommon::clear_breadcrumbs();
#if any br links exists, add them to the breadcrumbs
if (exists($args->{'bread_crumbs'}) and ref($args->{'bread_crumbs'}) eq 'ARRAY') {
@@ -9096,12 +9993,20 @@ sub start_page {
} else {
undef($menulink);
}
+ my $linkprotout;
+ if ($env{'request.deeplink.login'}) {
+ my $linkprotout = &Apache::lonmenu::linkprot_exit();
+ if ($linkprotout) {
+ &Apache::lonhtmlcommon::add_breadcrumb_tool('tools',$linkprotout);
+ }
+ }
#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'},'',$menulink);
} else {
$result .= &Apache::lonhtmlcommon::breadcrumbs('','',$menulink);
}
+ }
}
return $result;
}
@@ -9143,7 +10048,7 @@ sub menucoll_in_effect {
if ($env{'request.course.id'}) {
$menucoll = $env{'course.'.$env{'request.course.id'}.'.menudefault'};
if ($env{'request.deeplink.login'}) {
- my ($deeplink_symb,$deeplink);
+ my ($deeplink_symb,$deeplink,$check_login_symb);
my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
if ($env{'request.noversionuri'} =~ m{^/(res|uploaded)/}) {
@@ -9153,11 +10058,21 @@ sub menucoll_in_effect {
$deeplink = $navmap->get_mapparam(undef,
&Apache::lonnet::declutter($env{'request.noversionuri'}),
'0.deeplink');
+ } else {
+ $check_login_symb = 1;
}
} else {
- $deeplink = &Apache::lonnet::EXT('resource.0.deeplink');
+ my $symb = &Apache::lonnet::symbread();
+ if ($symb) {
+ $deeplink = &Apache::lonnet::EXT('resource.0.deeplink',$symb);
+ } else {
+ $check_login_symb = 1;
+ }
}
} else {
+ $check_login_symb = 1;
+ }
+ if ($check_login_symb) {
$deeplink_symb = &deeplink_login_symb($cnum,$cdom);
if ($deeplink_symb =~ /\.(page|sequence)$/) {
my $mapname = &Apache::lonnet::deversion((&Apache::lonnet::decode_symb($deeplink_symb))[2]);
@@ -9170,7 +10085,7 @@ sub menucoll_in_effect {
}
}
if ($deeplink ne '') {
- my ($state,$others,$listed,$scope,$protect,$display) = split(/,/,$deeplink);
+ my ($state,$others,$listed,$scope,$protect,$display,$target) = split(/,/,$deeplink);
if ($display =~ /^\d+$/) {
$deeplinkmenu = 1;
$menucoll = $display;
@@ -9225,6 +10140,50 @@ sub symb_from_tinyurl {
}
}
+sub usable_exttools {
+ my %tooltypes;
+ if ($env{'request.course.id'}) {
+ if ($env{'course.'.$env{'request.course.id'}.'.internal.exttool'}) {
+ if ($env{'course.'.$env{'request.course.id'}.'.internal.exttool'} eq 'both') {
+ %tooltypes = (
+ crs => 1,
+ dom => 1,
+ );
+ } elsif ($env{'course.'.$env{'request.course.id'}.'.internal.exttool'} eq 'crs') {
+ $tooltypes{'crs'} = 1;
+ } elsif ($env{'course.'.$env{'request.course.id'}.'.internal.exttool'} eq 'dom') {
+ $tooltypes{'dom'} = 1;
+ }
+ } else {
+ my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+ my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+ my $crstype = lc($env{'course.'.$env{'request.course.id'}.'.type'});
+ if ($crstype eq '') {
+ $crstype = 'course';
+ }
+ if ($crstype eq 'course') {
+ if ($env{'course.'.$env{'request.course.id'}.'internal.coursecode'}) {
+ $crstype = 'official';
+ } elsif ($env{'course.'.$env{'request.course.id'}.'.internal.textbook'}) {
+ $crstype = 'textbook';
+ } elsif ($env{'course.'.$env{'request.course.id'}.'.internal.lti'}) {
+ $crstype = 'lti';
+ } else {
+ $crstype = 'unofficial';
+ }
+ }
+ my %domdefaults = &Apache::lonnet::get_domain_defaults($cdom);
+ if ($domdefaults{$crstype.'domexttool'}) {
+ $tooltypes{'dom'} = 1;
+ }
+ if ($domdefaults{$crstype.'exttool'}) {
+ $tooltypes{'crs'} = 1;
+ }
+ }
+ }
+ return %tooltypes;
+}
+
sub wishlist_window {
return(<<'ENDWISHLIST');